Патч метода порицаемого класса - PullRequest
0 голосов
/ 04 марта 2020

Мой код имеет следующую структуру:

У меня есть класс MyClass, который наследуется от BaseClass (это случайная точка, а не источник моей проблемы). Затем у меня есть другой класс MyClassManager, который вызывает методы MyClass.

. Я пишу unittest для метода MyClassManager, и я хочу контролировать возвращаемое значение одного из методов MyClass во время автоматического определения остальных.

В моем тесте я создал Mock для MyClass, исправив класс с помощью autospec=True. Затем я попытался пропатчить метод MyClass.method_to_patch и заменить его на Substitute.substitute_method. Пока все хорошо.

Но теперь, когда я запускаю тест, менеджер классов создает экземпляр MyClass, который является полностью автоматически заданным Mock, но он не исправляет метод, который я хочу заменить.

Есть ли способ объединить эти два patch декоратора для достижения того, чего я хочу?

class Substitute:

    def substitute_method(self, arg1, arg2):
        print("Running substitute method")
        return (arg1 > 0 and arg2 > 0)


class BaseClass:

    def method_to_patch(self, arg1, arg2):
        return arg1 == arg2


class MyClass(BaseClass):

    def myclass_method(self):
        print("myclass method called")


class MyClassManager:

    def method_to_test(self):
        my_class = MyClass()
        my_class.myclass_method()
        my_class.method_to_patch(10, 100)


class TestMyClass(unittest.TestCase):

    @patch.object(MyClass, "method_to_patch", Substitute.substitute_method)
    @patch("__main__.MyClass", autospec=True)
    def test_method_to_test(self, mock_class):
        class_manager = MyClassManager()
        class_manager.method_to_test()
        print(mock_class.call_count)


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

Ответы [ 2 ]

0 голосов
/ 05 марта 2020

Я нашел ключ к ответу на следующей странице, где говорится о насмешливых вызовах вложенных атрибутов: https://www.integralist.co.uk/posts/mocking-in-python/. Та же логика c применяется к вызовам методов.

Недостаточно вручную настроить макет объекта - вам нужно настроить return_value макет объекта.

Так вот как должен выглядеть тест:

class TestMyClass(unittest.TestCase):

    @patch("__main__.MyClass", autospec=True)
    def test_method_to_test(self, mock_class):
        mock_class.return_value.method_to_patch = Substitute.substitute_method
        class_manager = MyClassManager()
        class_manager.method_to_test()
        print(mock_class.call_count)

Теперь у меня есть фиктивный объект вместо MyClass, поэтому MyClass.myclass_method также имитируется, но я могу заменить Substitute.substitute_method вместо MyClass.method_to_patch как Я хотел.

Последнее замечание - substitute_method на самом деле staticmethod, поэтому он должен выглядеть так:

class Substitute:

    @staticmethod
    def substitute_method(arg1, arg2):
        print("Running substitute method")
        return (arg1 > 0 and arg2 > 0)
0 голосов
/ 04 марта 2020

Чтобы смоделировать метод в классе для возврата указанного c значения, используйте @patch. объект. Чтобы смоделировать метод в классе с помощью @patch. объект, но при каждом вызове возвращать другое значение, используйте side_effect.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...