我有一个函数以 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", ...])
我也可以代理模拟。这使得断言很干净,但想想有点奇怪,每次实际函数的参数发生变化时都需要更新 proxy()
函数。
@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"])))
关于python - 如何使用生成器参数验证 Python 模拟调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66266538/