[英]Using Python mock to spy on calls to an existing object
我正在使用 Python 模拟模块进行测试。 我想用模拟替换活动的 object,并自动将对模拟 object 的所有调用转发到原始 object。 我认为这在标准测试术语中被称为“间谍”。 目前我正在做一个测试:
# Insert a mock replacement
orig_active_attr = server.active_attr
server.active_attr = mock.Mock()
# Set up side effects to 'proxy' to the original object
server.active_attr.meth1.side_effect = orig_active_attr.meth1
server.active_attr.meth2.side_effect = orig_active_attr.meth2
# Call the method being tested
server.method_being_tested()
# Assert stuff on the mock.
server.active_attr.meth2.assert_called_once()
如果模拟上的所有方法调用都可以在没有样板的情况下自动转发到实时 object,那就太好了。
我似乎偶然发现了解决方案:
import mock
class A(object):
def meth(self, a):
return a
a = A()
ma = mock.Mock(wraps=a)
似乎可以正常使用函数,方法和属性,但不适用于类或实例属性。
请参阅文档 。
您可以使用Python的模拟模块在实例方法上进行Spying时的建议使用patch.object(wraps=obj_instance)
。
例如:
from mock import patch
class Foo(object):
def bar(self, x, y):
return x + y + 1
def test_bar():
foo = Foo()
with patch.object(foo, 'bar', wraps=foo.bar) as wrapped_foo:
foo.bar(1, 2)
wrapped_foo.assert_called_with(1, 2)
您可以使用一个简单的函数来遍历所有方法并配置您的模拟
import inspect
def spy_mock(instance):
members = inspect.getmembers(instance, inspect.ismethod)
attrs = {'%s.side_effect' % k:v for k,v in members}
return mock.Mock(**attrs)
server.active_attr = spy_mock(server.active_attr)
扩展Wes McKinney 的模式(通过 Wilfred Hughes 回答),这里是如何监视 object 的方法/成员,其中 object 被导入到被测模块中。
请注意,此解决方案符合 Python 2.x
被测模块:
import object
def function_in_module_under_test():
object.method_from_imported_object()
在 method_from_imported_object 上测试间谍断言:
from unittest import mock
import module_under_test
def test_method(self):
with mock.patch.object(
module_under_test.object,
"method_from_imported_object",
module_under_test.object.method_from_imported_object,
) as spy_method_from_imported_object:
# Demonstrate that subsequent spy asserts here, can be trusted
spy_method_from_imported_object.assert_not_called()
# now Test
module_under_test.function_in_module_under_test()
spy_method_from_imported_object.assert_called_once()
以下是如何仅模拟datetime.date.today()
,将其余的datetime
调用转发到datetime
模块:
from unittest import mock, TestCase
import foo_module
class FooTest(TestCase):
@mock.patch(f'{foo_module.__name__}.datetime', wraps=datetime)
def test_something(self, mock_datetime):
# mock only datetime.date.today()
mock_datetime.date.today.return_value = datetime.date(2019, 3, 15)
# other calls to datetime functions will be forwarded to original datetime
foo_module
导入datetime
并使用date.today
以外的许多其他datetime
函数。
如果你使用 pytest,pytest-mock package 有一个方便的间谍object。
class Foo(object):
def bar(self, v):
return v * 2
def test_spy_method(mocker):
foo = Foo()
spy = mocker.spy(foo, 'bar')
assert foo.bar(21) == 42
spy.assert_called_once_with(21)
assert spy.spy_return == 42
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.