Python - 当 `new` 参数不是 DEFAULT 时,为什么模拟补丁装饰器不将模拟对象传递给测试函数
Python - why mock patch decorator does not pass the mocked object to the test function when `new` argument is not DEFAULT
在 Python 3.6 中,我使用 unittest.mock.patch
来修补这样的函数:
class SampleTest(TestCase):
@mock.patch('some_module.f')
def test_f(self, mocked_f):
f()
mocked_f.assert_called()
这将 mock.MagicMock()
作为 mocked_f
传递,一切正常。但是,当我想使用自定义模拟对象而不是使用 new
参数的默认 mock.MagicMock()
时,补丁装饰器不会将模拟对象传递给 test_f
方法。 运行 此代码将引发 TypeError
:
class SampleTest(TestCase):
@mock.patch('some_module.f', new=lambda: 8)
def test_f(self, mocked_f):
f()
mocked_f.assert_called()
TypeError: test_f() missing 1 required positional argument: 'mocked_f'
我的问题是:为什么会这样?
来自文档(强调我的):
If patch()
is used as a decorator and new is omitted, the created mock is passed in as an extra argument to the decorated function.
在显式使用 new
的情况下,装饰器不会将模拟对象作为参数传递(可能是因为它希望您已经拥有无需参数即可使用的引用)。
在这种情况下,解决方法是在 将其传递给您的测试后配置模拟:
class SampleTest(TestCase):
@mock.patch('tests.f')
def test_f(self, mocked_f):
mocked_f.return_value = 8
# or
# mocked_f.side_effect = lambda: 8
f()
mocked_f.assert_called()
我认为当指定 new
时模拟对象没有传递给修饰函数的原因可能是正确的,因为您通常已经有对该对象的引用,所以不要不需要将它传递到装饰函数中。
但是请注意,如果您使用 new_callable
而不是 new
,那么模拟对象 将传递给装饰函数 。这是有道理的,因为您通常不会引用从可调用对象返回的对象。
因此您可以执行以下操作:
def my_custom_mock_factory():
my_mock = mock.Mock()
# customisations to my_mock
return my_mock
class SampleTest(TestCase):
@mock.patch('some_module.f', new_callable=my_custom_mock_factory)
def test_f(self, mocked_f):
f()
mocked_f.assert_called()
在 Python 3.6 中,我使用 unittest.mock.patch
来修补这样的函数:
class SampleTest(TestCase):
@mock.patch('some_module.f')
def test_f(self, mocked_f):
f()
mocked_f.assert_called()
这将 mock.MagicMock()
作为 mocked_f
传递,一切正常。但是,当我想使用自定义模拟对象而不是使用 new
参数的默认 mock.MagicMock()
时,补丁装饰器不会将模拟对象传递给 test_f
方法。 运行 此代码将引发 TypeError
:
class SampleTest(TestCase):
@mock.patch('some_module.f', new=lambda: 8)
def test_f(self, mocked_f):
f()
mocked_f.assert_called()
TypeError: test_f() missing 1 required positional argument: 'mocked_f'
我的问题是:为什么会这样?
来自文档(强调我的):
If
patch()
is used as a decorator and new is omitted, the created mock is passed in as an extra argument to the decorated function.
在显式使用 new
的情况下,装饰器不会将模拟对象作为参数传递(可能是因为它希望您已经拥有无需参数即可使用的引用)。
在这种情况下,解决方法是在 将其传递给您的测试后配置模拟:
class SampleTest(TestCase):
@mock.patch('tests.f')
def test_f(self, mocked_f):
mocked_f.return_value = 8
# or
# mocked_f.side_effect = lambda: 8
f()
mocked_f.assert_called()
我认为当指定 new
时模拟对象没有传递给修饰函数的原因可能是正确的,因为您通常已经有对该对象的引用,所以不要不需要将它传递到装饰函数中。
但是请注意,如果您使用 new_callable
而不是 new
,那么模拟对象 将传递给装饰函数 。这是有道理的,因为您通常不会引用从可调用对象返回的对象。
因此您可以执行以下操作:
def my_custom_mock_factory():
my_mock = mock.Mock()
# customisations to my_mock
return my_mock
class SampleTest(TestCase):
@mock.patch('some_module.f', new_callable=my_custom_mock_factory)
def test_f(self, mocked_f):
f()
mocked_f.assert_called()