[英]How do you mock patch a python class and get a new Mock object for each instantiation?
OK,行,
I know this is mentioned in the manual , and probably has to do with side_effect
and/or return_value
, but a simple, direct example will help me immensely.我知道手册中提到了这一点,可能与side_effect
和/或return_value
,但是一个简单、直接的示例将极大地帮助我。
I have:我有:
class ClassToPatch():
def __init__(self, *args):
_do_some_init_stuff()
def some_func():
_do_stuff()
class UUT():
def __init__(self, *args)
resource_1 = ClassToPatch()
resource_2 = ClassToPatch()
Now, I want to unit test the UUT
class, and mock the ClassToPatch
.现在,我想对UUT
类进行单元测试,并模拟ClassToPatch
。 Knowing the UUT
class will instantiate exactly two ClassToPatch
objects, I want the Mock framework to return a new Mock object for each instantiation, so I can later assert calls on each separately.知道UUT
类将实例化两个ClassToPatch
对象,我希望 Mock 框架为每个实例化返回一个新的 Mock 对象,以便我稍后可以分别断言对每个对象的调用。
How do I achieve this using the @patch
decorator in a test case?如何在测试用例中使用@patch
装饰器来实现这一点? Namely, how to fix the following code sample?即,如何修复以下代码示例?
class TestCase1(unittest.TestCase):
@patch('classToPatch.ClassToPatch',autospec=True)
def test_1(self,mock1,mock2):
_assert_stuff()
Here's a quick'n'dirty example to get you going:这是一个让您开始的快速示例:
import mock
import unittest
class ClassToPatch():
def __init__(self, *args):
pass
def some_func(self):
return id(self)
class UUT():
def __init__(self, *args):
resource_1 = ClassToPatch()
resource_2 = ClassToPatch()
self.test_property = (resource_1.some_func(), resource_2.some_func())
class TestCase1(unittest.TestCase):
@mock.patch('__main__.ClassToPatch', autospec = True)
def test_1(self, mock1):
ctpMocks = [mock.Mock(), mock.Mock()]
ctpMocks[0].some_func.return_value = "funky"
ctpMocks[1].some_func.return_value = "monkey"
mock1.side_effect = ctpMocks
u = UUT()
self.assertEqual(u.test_property, ("funky", "monkey"))
if __name__ == '__main__':
unittest.main()
I've added test_property
to UUT so that the unit test does something useful.我已经将test_property
添加到 UUT 以便单元测试做一些有用的事情。 Now, without the mock test_property
should be a tuple containing the ids of the two ClassToPatch
instances.现在,没有模拟test_property
应该是一个包含两个ClassToPatch
实例的 id 的元组。 But with the mock it should be the tuple: ("funky", "monkey")
.但是对于模拟,它应该是元组: ("funky", "monkey")
。
I've used the side_effect
property of the mock object so that a different instance of ClassToPatch
is returned on each call in the UUT
initialiser.我使用了模拟对象的side_effect
属性,以便在UUT
初始化程序中的每次调用时返回ClassToPatch
的不同实例。
Hope this helps.希望这可以帮助。
Edit: Oh, by the way, when I run the unit test I get:编辑:哦,顺便说一句,当我运行单元测试时,我得到:
.
----------------------------------------------------------------------
Ran 1 test in 0.004s
OK
Here is another version which is more generic to handle any number of instances created:这是另一个更通用的版本,可以处理创建的任意数量的实例:
class TestUUT:
def test_init(self, mocker):
class MockedClassToPatchMeta(type):
static_instance = mocker.MagicMock(spec=ClassToPatch)
def __getattr__(cls, key):
return MockedClassToPatchMeta.static_instance.__getattr__(key)
class MockedClassToPatch(metaclass=MockedClassToPatchMeta):
original_cls = ClassToPatch
instances = []
def __new__(cls, *args, **kwargs):
MockedClassToPatch.instances.append(
mocker.MagicMock(spec=MockedClassToPatch.original_cls))
MockedClassToPatch.instances[-1].__class__ = MockedClassToPatch
return MockedClassToPatch.instances[-1]
mocker.patch(__name__ + '.ClassToPatch', new=MockedClassToPatch)
UUT()
# since your original code created two instances
assert 2 == len(MockedClassToPatch.instances)
If you need more thorough validation for each instance you can access MockedClassToPatch.instances[0]
or MockedClassToPatch.instances[1]
.如果您需要对每个实例进行更彻底的验证,您可以访问MockedClassToPatch.instances[0]
或MockedClassToPatch.instances[1]
。
I've also created a helper library to generate the meta class boilerplate for me.我还创建了一个帮助程序库来为我生成元类样板。 To generate the needed code for your example I wrote:要为您的示例生成所需的代码,我写道:
print(PytestMocker(mocked=ClassToPatch, name=__name__).mock_classes().mock_classes_static().generate())
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.