我正在为我们正在开发的一些库编写单元测试。该库利用
requests.post()
向外部服务器执行 POST HTTP 请求。
在我的 UT 中,我显然不想联系真实的服务器,而是想模拟响应。
为此,我编写了一个函数,如下所示:
def mocked_post(url, headers, data, **kwargs):
response = Mock()
# Some logic, irrelevant here.
return response
我在我的单元测试类周围修补了这个函数:
@patch('mylib.requests.post', mocked_post)
class MyTest(TestCase):
def test_foo(self):
# Some test logic
这工作完美。
现在我想获取对我的模拟函数的调用次数。我尝试过
mocked_post.call_count
,但那不存在。我尝试在很多不同的对象(包括mylib.requests.post
)上找到这个属性,但到目前为止还没有成功。
我如何访问这个模拟函数的
call_count
?
我不会在这里使用
mocked_post
作为 new
参数。我会设置一个新的 side_effect
的
Mock
属性:
@patch('mylib.requests.post')
class MyTest(TestCase):
def test_foo(self, post_mock):
post_mock.side_effect = mocked_post
# Some test logic
self.assertEqual(post_mock.call_count, 3)
现在您拥有
Mock
为您生成的 patch
对象作为所有测试方法的参数,因此您可以测试调用该模拟的次数。
您还应该能够在装饰器中设置
side_effect
属性,以应用于所有测试:
@patch('mylib.requests.post', side_effect=mocked_post)
class MyTest(TestCase):
def test_foo(self, post_mock):
# Some test logic
self.assertEqual(post_mock.call_count, 3)
但是,您仍然无法访问返回的
response
对象;您可能希望从 mock.DEFAULT
返回 mocked_post
,而不是在函数中创建一个,这样您就可以使用 post_mock.return_value
对返回的对象进行进一步的断言。
9年后到来,但你也可以这样做:
@patch('mylib.requests.post')
class MyTest(TestCase):
def test_foo(self, post_mock):
# Some test logic
assert post_mock.call_count == 3
#if you need to mock the return value
post_mock.return_value = "success"
如果您只想计算调用次数而不修改方法的行为,您可以使用
wrap
参数,如下所示:
with mock.patch.object(FTPDownloader, 'ftp_get_stat', wraps=FTPDownloader.ftp_get_stat) as mock_ftp:
# Your code with calls to FTPDownloader.ftp_get_stat()
# The real ftp_get_stat() will be called as many times as necessary
assert mock_ftp.call_count == 3
当您向
wraps
参数(使用 mock.patch.object
、Mock
或 MagicMock
构造函数)提供对象时,它会创建一个模拟对象,该对象将所有调用委托给包装对象,同时仍然允许您对方法的调用进行计数。