模拟外部API以进行Python测试 [英] Mocking external API for testing with Python

查看:53
本文介绍了模拟外部API以进行Python测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

上下文

我正在尝试为查询外部API的函数编写测试.这些函数将请求发送到API,获取响应并进行处理.在我的测试中,我想使用在本地运行的Mock服务器模拟外部API.到目前为止,模拟服务器已成功运行并响应自定义GET查询.

问题

外部API使用类型为< class'dict'> 的对象进行响应,而显然我可以从模拟服务器中获得的只是类型为< class'bytes的响应'> .模拟服务器正在从磁盘中获取预定义的数据,并通过流返回它们.由于我无法模拟外部API,因此由于响应类型错误,测试会抛出错误消息.

以下是我的代码片段以及一些解释.

1.. setUp()函数:

setUp函数在测试套件的开始运行.它负责在运行测试之前配置和运行服务器:

  def setUp(self):self.factory = APIRequestFactory()#配置模拟服务器self.mock_server_port = get_free_port()self.mock_server = HTTPServer(('localhost',self.mock_server_port),MockServerRequestHandler)#在单独的线程中运行模拟服务器self.mock_server_thread =线程(target = self.mock_server.serve_forever)self.mock_server_thread.setDaemon(真实)self.mock_server_thread.start() 

2.MockServerClassHandler:

  class MockServerRequestHandler(BaseHTTPRequestHandler):def do_GET():如果re.search(config.SYSTEM_STATUS_PATTERN,self.path):#响应状态码self.send_response(requests.codes.ok)#响应头self.send_header("Content-Type","application/json; charset = utf-8")self.end_headers()#从文件中清除响应并提供服务使用open('/path/to/my-json-formatted-file')作为data_file:response_content = json.dumps(json.load(data_file))#写入需要类似字节输入的流#https://docs.python.org/2/library/basehttpserver.htmlself.wfile.write(response_content.encode('utf-8'))返回 

据我从官方文档的理解,这是一个 BaseHTTPRequestHandler只能通过在预定义的流( wfile )中写入内容来提供其响应的内容,该流需要给定一个(如我所引用的错误消息)类似字节的变量.>

所以我的问题是:

  • 是否有一种方法可以使我的模拟服务器以字节以外的其他类型的内容进行响应?(JSON,python dicts ...)
  • 在我测试的函数中编写一段将字节变量转换为Python dict的代码是否安全,以使我可以在我的模拟服务器上对其进行测试?还是违反了某些测试原则?
  • 是否还有另一种编写可响应JSON和python dict的服务器的方法?

解决方案

在注释中,听起来好像您已经解决了主要问题,但是您有兴趣学习如何模拟Web请求而不是启动虚拟Web.服务器.

这是模拟网上的教程API请求和详细信息在文档中.如果您使用的是旧版Python,则可以将 mock 模块作为与PyPI分开的软件包安装.

以下是本教程的摘录:

  @patch('project.services.requests.get')def test_getting_todos_when_response_is_ok(mock_get):待办事项= [{'userId':1,'id':1,'title':'铺床',完成":错误}]#配置模拟返回一个OK状态码的响应.另外,模拟应该有#一个json()方法,该方法返回待办事项列表.mock_get.return_value =模拟值(ok = True)mock_get.return_value.json.return_value =待办事项#调用服务,该服务将向服务器发送请求.响应= get_todos()#如果请求发送成功,则希望返回响应.assert_list_equal(response.json(),待办事项) 

Context

I am trying to write tests for functions that query an external API. These functions send requests to the API, get responses and process them. In my tests, I want to simulate the external API with a Mock server that is ran locally. So far, the mock server is ran successfully and responds to custom GET queries.

The problem

The external API responds with objects of type <class 'dict'>, while apparently all I can get from my mock server is a response of type <class 'bytes'>. The mock server is fetching pre-defined data from disk and returning them through a stream. Since I can not simulate the external API, my tests throw error messages because of the wrong types of responses.

Following are snippets of my code with some explanations.

1. setUp() function:

The setUp function is ran at the beginning of the test suite. It is responsible of configuring and running the server before running the tests:

def setUp(self):
    self.factory = APIRequestFactory()
    # Configuring the mock server
    self.mock_server_port = get_free_port()
    self.mock_server = HTTPServer(('localhost', self.mock_server_port), MockServerRequestHandler)
    # Run the mock server in a separate thread
    self.mock_server_thread = Thread(target=self.mock_server.serve_forever)
    self.mock_server_thread.setDaemon(True)
    self.mock_server_thread.start()

2. The MockServerClassHandler:

class MockServerRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
    if re.search(config.SYSTEM_STATUS_PATTERN, self.path):
        # Response status code
        self.send_response(requests.codes.ok)
        # Response headers
        self.send_header("Content-Type", "application/json; charset=utf-8")
        self.end_headers()
        # Purge response from a file and serve it
        with open('/path/to/my-json-formatted-file') as data_file:
            response_content = json.dumps(json.load(data_file))

        # Writing to a stream that need bytes-like input
        # https://docs.python.org/2/library/basehttpserver.html
        self.wfile.write(response_content.encode('utf-8'))
        return

To my understanding from the official documentation, a BaseHTTPRequestHandler can only serve the content of his response through writing in a predefined stream (wfile) which needs to be given (and I am quoting an error message) a byte-like variable.

So my questions are:

  • Is there a way to make my mock server respond with other types of content than bytes? (JSON, python dicts ...)
  • Is it safe to write, in the functions that I test, a piece of code that will convert the bytes variables to Python dicts, just so I can test them with my mock server? Or is this violating some principles of testing?
  • Is there another way of writing a server that responds with JSON and python dicts?

解决方案

In the comments, it sounds like you solved your main problem, but you're interested in learning how to mock out the web requests instead of launching a dummy web server.

Here's a tutorial on mocking web API requests, and the gory details are in the documentation. If you're using legacy Python, you can install the mock module as a separate package from PyPI.

Here's a snippet from the tutorial:

@patch('project.services.requests.get')
def test_getting_todos_when_response_is_ok(mock_get):
    todos = [{
        'userId': 1,
        'id': 1,
        'title': 'Make the bed',
        'completed': False
    }]

    # Configure the mock to return a response with an OK status code. Also, the mock should have
    # a `json()` method that returns a list of todos.
    mock_get.return_value = Mock(ok=True)
    mock_get.return_value.json.return_value = todos

    # Call the service, which will send a request to the server.
    response = get_todos()

    # If the request is sent successfully, then I expect a response to be returned.
    assert_list_equal(response.json(), todos)

这篇关于模拟外部API以进行Python测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆