通过使用多个灯具,可以实现您想要的结果.
注意:我最低限度地修改了您的示例,以便我的答案中的代码是自包含的,但您应该能够轻松地将其调整到您的用例.
在myapi.py中:
import requests
class MyApi:
def get_uuid(self):
return requests.get('http://httpbin.org/uuid').json()['uuid']
在test.py中:
from unittest import mock
import pytest
from myapi import MyApi
FAKE_RESPONSE_PAYLOAD = {
'uuid': '12e77ecf-8ce7-4076-84d2-508a51b1332a',
}
@pytest.fixture
def mocked_requests():
with mock.patch('myapi.requests') as _mocked_requests:
response_mock = mock.Mock()
response_mock.json.return_value = FAKE_RESPONSE_PAYLOAD
_mocked_requests.get.return_value = response_mock
yield _mocked_requests
@pytest.fixture
def api():
return MyApi()
def test_requests_was_called(mocked_requests, api):
assert not mocked_requests.get.called
api.get_uuid()
assert mocked_requests.get.called
def test_uuid_is_returned(mocked_requests, api):
uuid = api.get_uuid()
assert uuid == FAKE_RESPONSE_PAYLOAD['uuid']
def test_actual_api_call(api): # Notice we don't mock anything here!
uuid = api.get_uuid()
assert uuid != FAKE_RESPONSE_PAYLOAD['uuid']
我没有定义一个返回元组的灯具,而是定义了两个灯具,它们可以独立地用于测试.组成这样的固定装置的一个优点是它们可以独立使用,例如,最后一个测试实际上是调用API,只是因为没有使用mock_requests fixture.
注意 – 要直接回答问题标题 – 你也可以通过简单地将它添加到参数中来使mocked_requests成为api fixture的先决条件,如下所示:
@pytest.fixture
def api(mocked_requests):
return MyApi()
如果运行测试套件,您将看到它有效,因为test_actual_api_call将不再通过.
如果进行此更改,则在测试中使用api fixture也意味着在mocked_requests的上下文中执行它,即使您未在测试函数的参数中直接指定后者.它仍然可以明确地使用它,例如如果你想在返回的模拟上做断言.