上下文
我正在尝试为查询外部API的函数编写测试。这些函数向API发送请求,获取响应并处理它们。在我的测试中,我想用本地运行的Mock服务器模拟外部API。到目前为止,模拟服务器已成功运行并响应自定义GET查询。
问题
外部API使用类型为<class 'dict'>
的对象进行响应,而显然我可以从我的模拟服务器获得的是<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()
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
根据我对official documentation的理解,BaseHTTPRequestHandler只能通过写入预定义的流(wfile
)来提供他的响应内容,这个流需要给出(我引用错误消息)一个类似字节的变量。
所以我的问题是:
在评论中,听起来你解决了你的主要问题,但你有兴趣学习如何模拟Web请求而不是启动虚拟Web服务器。
这里是关于模拟Web API请求的a tutorial,并且血腥细节在the documentation中。如果您使用的是旧版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)