[英]Mocking a Standard Library function with and without pytest-mock
为了进行测试,我想模拟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。仍然被调用而不是模拟
我试图直接使用现在是Python3一部分的模拟包:
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()
而不是指定的模拟。
在我的测试案例中,成功实现模拟的哪些步骤是错误的或错过了?
我花了更多时间研究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')
修补程序装饰程序需要从测试中的系统调用的功能名称 (完整路径)。 模拟文档中对此进行了明确说明。 以下段落总结了补丁装饰器的这一原理:
修补程序通过(临时)将名称指向的对象更改为另一个对象来工作。 可以有许多名称指向任何单个对象,因此要使修补程序起作用,必须确保修补受测系统使用的名称。
尝试使用monkeypatch 。 您可以在示例中看到它们如何“ monkeypatch” os.getcwd
返回所需的路径。 在您的情况下,我认为这应该可行:
monkeypatch.setattr("shutil.which", lambda: "/path/foo.exe")
将which
方法注入到您的方法或对象中将使您可以在没有pytest-mock
情况下模拟依赖pytest-mock
。
def _find_foo(self, which_fn=shutil.which) -> Path:
foo_exe = which_fn('foo', path=None)
if foo_exe:
return Path(foo_exe)
else:
return None
def test_find_foo():
mock_which = Mock(return_value = '/path/foo.exe')
foo_path = obj._find_foo(which_fn=mock_which)
assert foo_path is '/path/foo.exe'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.