行,
我知道这在manual中有提及,可能与side_effect
和/或return_value
有关,但一个简单直接的例子对我有很大的帮助。
我有:
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()
现在,我想对UUT
类进行单元测试,并模拟ClassToPatch
。知道UUT
类将实例化两个ClassToPatch
对象,我希望Mock框架为每个实例化返回一个新的Mock对象,所以我可以稍后在每个实例上断言。
如何在测试用例中使用@patch
装饰器实现此目的?即,如何修复以下代码示例?
class TestCase1(unittest.TestCase):
@patch('classToPatch.ClassToPatch',autospec=True)
def test_1(self,mock1,mock2):
_assert_stuff()
答案 0 :(得分:29)
这是一个让你前进的快速例子:
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()
我已将test_property
添加到UUT,以便单元测试可以执行一些有用的操作。现在,没有mock test_property
应该是一个包含两个ClassToPatch
实例的id的元组。但是使用模拟它应该是元组:("funky", "monkey")
。
我使用了模拟对象的side_effect
属性,以便在ClassToPatch
初始化程序的每次调用中返回UUT
的不同实例。
希望这有帮助。
编辑:哦,顺便说一下,当我运行单元测试时,我得到了:
.
----------------------------------------------------------------------
Ran 1 test in 0.004s
OK
答案 1 :(得分:0)
这是另一个版本,可以处理创建的任意数量的实例:
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)
如果您需要对每个实例进行更彻底的验证,则可以访问MockedClassToPatch.instances[0]
或MockedClassToPatch.instances[1]
。
我还创建了a helper library来为我生成元类样板。为了生成您的示例所需的代码,我写道:
print(PytestMocker(mocked=ClassToPatch, name=__name__).mock_classes().mock_classes_static().generate())