Python 模拟工厂子 类 和方法

Python Mock Factory Sub Classes and Methods

我需要模拟 MyClassFactory 其中 returns 一个 MyClass 对象。这个对象有一个方法 getNum 我也需要模拟。我不确定如何执行此操作,因为工厂不再 returns MyClass,而是 <MagicMock name='mock().create()'...>.

import unittest
from mock import MagicMock, Mock, patch

class MyClass:
    def getNum(self):
        return 10

class MyClassFactory:
    def create(self):
        return MyClass()

class Runner:
    def foo(self):
        myClassFactory = MyClassFactory()
        myClass = myClassFactory.create()

        num = myClass.getNum()

        if num == 10:
            print("foo successful")
        else:
            print("foo fail, num={}".format(num))

class TestRoute(unittest.TestCase):
    # Attempt at patching the methods
    @patch("__main__.MyClassFactory", create=True, new=MagicMock())
    @patch("__main__.MyClass", create=True, new=MagicMock())
    @patch("__main__.MyClass.getNum", create=True, new=MagicMock(return_value=11))
    def test_foo_fail(self):
        runner = Runner()
        runner.foo()

if __name__ == '__main__':
    unittest.main()

实际输出:

foo fail, num=<MagicMock name='mock().create().getNum()' id='140554774258128'>

期望的输出:

foo fail, num=11

这个<MagicMock name='mock().create().getNum()'...>不是我想要的。我试图将 return_value=11 用于模拟方法,但它没有被调用。

TLDR:我有一个工厂需要模拟。它returns一个class。 class 有一个方法,我还需要模拟我做不到的 return_value 。基本上我想把 mock().create().getNum() 变成 11.

这是你的第一个补丁

@patch("__main__.MyClass", create=True, new=MagicMock())

用 MagicMock() 替换了“main.MyClass”的 class 实例化。所以下一个补丁:

@patch("__main__.MyClass.getNum", create=True, new=MagicMock(return_value=11))

最终尝试调用 MagicMock() 对象的方法而不是原始的 main.MyClass,这会导致您看到的输出。

You need to attach mocks as attributes and set up each child mock.与其在测试之前打补丁,不如在调用 foo 之前打补丁。

import unittest
from mock import MagicMock, Mock, patch

class MyClass:
    def getNum(self):
        return 10

class MyClassFactory:
    def create(self):
        return MyClass()

class Runner:
    def foo(self):
        myClassFactory = MyClassFactory()
        myClass = myClassFactory.create()
        print(myClassFactory)
        print(myClass)
        num = myClass.getNum()
        if num == 10:
            print("foo successful")
        else:
            print("foo fail, num={}".format(num))

class TestRoute(unittest.TestCase):
    def test_foo_fail(self):
        getNumMock = MagicMock(return_value = 20)

        myClassMock = MagicMock()
        myClassMock.getNum = getNumMock

        createMock = MagicMock(return_value = myClassMock)

        myClassFactoryMock = MagicMock()

        createMock.attach_mock(getNumMock, "getNum")
        myClassFactoryMock.attach_mock(createMock, "create")

        with patch('__main__.MyClassFactory', create=True, return_value=myClassFactoryMock):
            runner = Runner()
            runner.foo()
if __name__ == '__main__':
    unittest.main()