Подклассы и методы Python Mock Factory - PullRequest
0 голосов
/ 04 октября 2019

Мне нужно смоделировать 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 Ответ

1 голос
/ 04 октября 2019

Происходит ваш первый патч

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

заменяет создание экземпляра класса " main .MyClass" на MagicMock (). Итак, следующий патч:

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

заканчивается попыткой вызова метода объекта MagicMock (), а не исходного main .MyClass, что приводит к выводу, который вы видите,

Вам необходимо прикрепить mock в качестве атрибутов и настроить каждую дочернюю 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()
...