模拟外部 API 以使用 Python 进行测试

Ana*_*our 3 python json unit-testing httpserver web-api-testing

语境

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

问题

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

以下是我的代码片段和一些解释。

1.setUp ()函数:

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

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()
Run Code Online (Sandbox Code Playgroud)

2. 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
Run Code Online (Sandbox Code Playgroud)

根据我对官方文档的理解,BaseHTTPRequestHandler只能通过在预定义流()中写入来提供其响应的内容wfile,需要给定(并且我引用错误消息)一个类似字节的变量。

所以我的问题是:

  • 有没有办法让我的模拟服务器响应字节以外的其他类型的内容?(JSON、Python 字典...)
  • 在我测试的函数中编写一段将字节变量转换为 Python 字典的代码是否安全,这样我就可以用我的模拟服务器测试它们?或者这违反了一些测试原则?
  • 是否有另一种方法可以编写用 JSON 和 python 字典响应的服务器?

Don*_*kby 5

在评论中,听起来您解决了主要问题,但您有兴趣学习如何模拟 Web 请求,而不是启动虚拟 Web 服务器。

这是一个关于模拟 Web API 请求的教程,详细信息位于文档中。如果您使用的是旧版 Python,则可以将该mock模块作为 PyPI 的单独包安装。

这是教程中的一个片段:

@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)
Run Code Online (Sandbox Code Playgroud)