如何模拟一个python类并为每个实例化获得一个新的模拟对象?

如何模拟一个python类并为每个实例化获得一个新的模拟对象?,python,mocking,python-unittest,python-mock,Python,Mocking,Python Unittest,Python Mock,好的, 我知道在中提到了这一点,可能与副作用和/或返回值有关,但一个简单、直接的例子将对我有很大帮助 我有: class ClassToPatch(): def __init__(self, *args): _do_some_init_stuff() def some_func(): _do_stuff() class UUT(): def __init__(self, *args) resource_1 = ClassToPa

好的,
我知道在中提到了这一点,可能与
副作用
和/或
返回值
有关,但一个简单、直接的例子将对我有很大帮助

我有:

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()

这里有一个简单的例子可以帮助你:

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()
我已经向UUT添加了
test\u属性
,以便单元测试可以做一些有用的事情。现在,如果没有mock
test\u属性,则应该是一个包含两个
ClassToPatch
实例ID的元组。但对于mock,它应该是元组:
(“funky”,“monkey”)

我使用了mock对象的属性,以便在
UUT
初始化器中的每次调用中返回不同的
ClassToPatch
实例

希望这有帮助

编辑:哦,顺便说一下,当我运行单元测试时,我得到:

.
----------------------------------------------------------------------
Ran 1 test in 0.004s

OK

下面是另一个更通用的版本,用于处理创建的任意数量的实例:

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]

我还创建了一个为我生成元类样板的工具。要为您的示例生成所需的代码,我编写了:

print(PytestMocker(mocked=ClassToPatch, name=__name__).mock_classes().mock_classes_static().generate())

(Python新手:)有没有办法修改它以在Python2.7下工作?我刚刚在Python2.7.9(win32)中运行了这段代码,它工作得很好。您遇到了什么错误?~$python--version python 2.7.5 AttributeError:没有属性'ClassToPatch'@srgerg您断言使用预期调用调用了mock,但没有断言使用无效调用调用了mock。我知道,通过使用
mock(spec=an_object)
创建一个mock,mock将只接受与
an_object
相同的调用,但我不知道在没有实例化对象的情况下如何执行,例如在这种情况下,mock应该是
类ClassToPatch的实例