a) 对我来说,解决方案是在测试函数内部使用with
块,而不是在测试函数之前使用@patch
装饰器:
class TestFoo:
def test_baa(self, my_fixture):
with patch(
'module.Class.function_to_patch',
MagicMock(return_value='mocked_result')
) as mocked_function_to_patch:
result= my_fixture.baa('mocked_input')
assert result == 'mocked_result'
mocked_function_to_patch.assert_has_calls([
call('mocked_input')
])
这个解决方案可以在类中正常工作(用于组织/分组我的测试方法)。使用with
语句块,您无需担心参数的顺序。我发现这比注入机制更加明确,但是如果您需要修补多个变量,则代码会变得丑陋。如果您需要修补许多依赖项,那可能意味着您要测试的函数做了太多的事情,因此您应该对其进行重构,例如提取一些功能到额外的函数中。
b) 如果您在类外部并且希望在测试方法中作为额外参数注入修补的对象... 请注意@patch
不支持将模拟对象定义为装饰器的第二个参数:
@patch('path.to.foo', MagicMock(return_value='foo_value'))
def test_baa(self, my_fixture, mocked_foo):
不起作用。
=> 确保将路径作为唯一参数传递给装饰器。然后在测试函数内定义返回值:
@patch('path.to.foo')
def test_baa(self, my_fixture, mocked_foo):
mocked_foo.return_value = 'foo_value'
不幸的是,在类内部似乎无法使用这个方法。
首先注入fixture(s), 然后注入@patch装饰器的变量(例如“mocked_foo”)。
注入的fixture名称“my_fixture”需要正确。它必须与修饰fixture函数的名称(或fixture装饰中使用的显式名称)匹配。
注入的patch变量名称“mocked_foo”没有遵循明确的命名规则。您可以根据需要选择名称,独立于相应的@patch装饰器路径。
如果您注入几个打补丁的变量,请注意顺序相反:属于最后一个@patch
装饰器的模拟实例首先被注入:
@patch('path.to.foo')
@patch('path.to.qux')
def test_baa(self, my_fixture, mocked_qux, mocked_foo):
mocked_foo.return_value = 'foo_value'
from unittest.mock import patch
和import mock
,我不得不删除import mock
语句,然后就不再抛出fixture 'mocked_instance' not found
错误了。 - Monsters X