出于测试目的,我想模拟 shutil.which(Python 3.5.1),它在简化方法 find_foo() 中调用
def _find_foo(self) -> Path:
foo_exe = which('foo', path=None)
if foo_exe:
return Path(foo_exe)
else:
return None
我正在使用 pytest 来实现我的测试用例。因此,我还想使用 pytest 扩展 pytest-mock。在下面,我使用 pytest + pytest-mock 粘贴了一个示例测试用例:
def test_find_foo(mocker):
mocker.patch('shutil.which', return_value = '/path/foo.exe')
foo_path = find_foo()
assert foo_path is '/path/foo.exe'
这种用 pytest-mock 进行模拟的方法是行不通的。 shutil.which 仍然被调用而不是模拟。
我尝试直接使用现在是 Python3 一部分的 mock 包:
def test_find_foo():
with unittest.mock.patch('shutil.which') as patched_which:
patched_which.return_value = '/path/foo.exe'
foo_path = find_foo()
assert foo_path is '/path/foo.exe'
遗憾的是结果是一样的。还调用了 shutil.which()
而不是指定的 mock。
在我的测试用例中,哪些成功实现模拟的步骤是错误的或遗漏的?
最佳答案
我研究了更多时间研究 unittest.mock 和 pytest-mock。我找到了一个简单的解决方案,无需使用补丁装饰器修改生产代码。在下面,我粘贴了一段代码片段,演示了使用 pytest-mock 的第三种方法:
def test_find_foo(mocker):
mocker.patch('__main__.which', return_value='/path/foo.exe')
foo_path = find_foo()
assert foo_path == Path('/path/foo.exe')
如果没有 pytest-mock(普通的 unittest-mock 和 @patch 装饰器),这个解决方案也可以工作。上面代码片段中重要的一行是
mocker.patch('__main__.which', return_value='/path/foo.exe')
补丁装饰器需要函数的名称(完整路径),该函数将从被测系统调用。这在 mock documentation 中有清楚的解释。 .以下段落总结了补丁装饰器的这一原理:
patch works by (temporarily) changing the object that a name points to with another one. There can be many names pointing to any individual object, so for patching to work you must ensure that you patch the name used by the system under test.
关于python - 使用和不使用 pytest-mock 模拟标准库函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38159765/