Как я могу вызвать метод для скопированного MagicMock в Python?

Я хочу проверить, что функция вызвала метод __copy__ (с заданным набором аргументов) для переданного ей объекта.

Поскольку для создания объекта требуется соединение с БД, я подумал, что должен смоделировать его и передать макет функции для теста.

Однако кажется, что __copy__ возвращает экземпляр mock (не уверен, Mock или MagicMock), который не позволяет вызывать на нем произвольные методы. Поскольку мой код вызывает методы для нового объекта, он возвращает приведенную ниже ошибку.

Как я могу утверждать, что метод __copy__ был вызван, а остальная часть функции по-прежнему работает без ошибок?

FWIW, я попытался назначить old_obj.__class__.return_value = MagicMock(), но, похоже, он не возвращает то, что я ему назначаю (т.е. я также назначил ... = 'foo', но он все равно вернул фиктивный объект).

Пример:

class MyClass:
    def __init__(self, my_name):
        self.my_name = my_name

    def speak(self):
        print('My name is ' + self.my_name)


def my_func(old_obj, new_name):
    new_obj = old_obj.__class__(new_name)
    new_obj.speak()


def test_my_func():
    old_obj = MagicMock()
    old_obj.my_name = 'foo'

    my_func(old_obj, 'bar')

Ошибка, вызванная py.test:

self = <MagicMock spec='str' id='4490339552'>, name = 'speak'

    def __getattr__(self, name):
        if name in {'_mock_methods', '_mock_unsafe'}:
            raise AttributeError(name)
        elif self._mock_methods is not None:
            if name not in self._mock_methods or name in _all_magics:
>               raise AttributeError("Mock object has no attribute %r" % name)
E               AttributeError: Mock object has no attribute 'speak'

person Jacob Beauchamp    schedule 07.08.2018    source источник


Ответы (1)


Вам необходимо указать аргумент spec при создании макета, иначе любые вызовы или атрибуты вернут объект mock.Mock().

import unittest
from unittest import mock

class MyClass:
    def __init__(self, my_name):
        self.my_name = my_name
    def speak(self):
        print('My name is ' + self.my_name)

def my_func(old_obj, new_name):
    new_obj = old_obj.__class__(new_name)
    new_obj.speak()

def test_my_func():
    old_obj = mock.MagicMock(spec=MyClass)
    old_obj.my_name = 'foo'
    my_func(old_obj, 'bar')

if __name__ == '__main__':
    unittest.main()
person wholevinski    schedule 17.08.2018