[英]How to verify Python mock calls with generator argument
我有一个 function 以Iterable
作为参数:
def print_me(vals: Iterable[str]) -> None:
...
它被一个生成器调用:
def run():
print_me((str(i) for i in range(10)))
我想修补和模拟print_me()
并验证它是否被特定参数调用。 使用普通的旧列表,这很容易:
mock.assert_called_with(["0", "1", ...])
但是对于生成器,因为它不能相等或重放,所以这更棘手。
我找到了一些解决方案。 我可以手动捕获参数,但如果多次调用该方法,它会变得更加混乱:
@patch('module.print_me')
def test(self, mock):
captured = None
mock.side_effect = lambda vals: captured = vals
run()
mock.assert_called_once_with(mock.ANY)
self.assertEqual(list(captured), ["0", "1", ...])
我也可以代理模拟。 这使得断言干净,但想想有点奇怪,并且每次实际函数的 arguments 更改时,都需要更新proxy()
function。
@patch('module.print_me')
def test(self, proxy_mock):
mock = mock.Mock()
def proxy(vals):
mock(list(vals))
proxy_mock.side_effect = proxy
run()
mock.assert_called_once_with(["0", "1"])
mock.assert_called_once_with(["2", "3"])
还有 PyHamcrest。 Hamcrest 在 Java 测试中确实很受欢迎,但在 Python 中似乎并不受欢迎。 也就是说,它做了我想要的:
@patch('module.print_me')
def test(self, mock):
run()
mock.assert_called_once_with(match_equality(contains_exactly(["2", "3"])))
有一种更简单的测试方法,那就是使用模拟 object 的call_args
属性。 call_args
返回一个元组,其中第一项是args
,第二项是kwargs
。 Python 3.8 中的语法略有更改,以允许通过执行mock_object.call_args.args
或mock_object.call_args.kwargs
访问这些项目,但我在 Python 3.7 上运行它,所以我采用更过时的方法。
@patch("src.module.print_me")
def test_run(mock_print):
run()
args, _ = mock_print.call_args
# grab the one and only call argument
gen = args[0]
expected = [str(i) for i in range(10)]
assert list(gen) == expected
正如您在上面的代码片段中看到的那样,我们获取输入到我们的模拟 object 的参数,使用它,然后将其与预期值进行比较。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.