Python Mock Factory子类和方法

时间:2019-10-03 23:20:53

标签: python mocking python-unittest

我需要模拟MyClassFactory,它返回一个MyClass对象。该对象还具有方法getNum,我也需要进行模拟。我不确定该如何执行此操作,因为工厂不再返回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:我有一个工厂需要模拟。它返回一个类。该类有一个方法,我还需要模拟不能做的return_value。基本上我想将mock().create().getNum()变成11

1 个答案:

答案 0 :(得分:1)

正在发生您的第一个补丁

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

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

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