Использование Python mock для отслеживания вызовов существующего объекта

Я использую модуль Python mock для тестов. Я хотел бы заменить активный объект макетом и автоматически выполнить все вызовы, сделанные для объекта mock, перенаправленного на исходный объект. Я думаю, что это называется "шпион" в стандартной терминологии тестирования. На данный момент я делаю внутри теста:

# Insert a mock replacement
orig_active_attr = server.active_attr
server.active_attr = mock.Mock()

# Set up side effects to 'proxy' to the original object
server.active_attr.meth1.side_effect = orig_active_attr.meth1
server.active_attr.meth2.side_effect = orig_active_attr.meth2

# Call the method being tested
server.method_being_tested()

# Assert stuff on the mock.
server.active_attr.meth2.assert_called_once()

Было бы хорошо, если бы все вызовы методов на mock могли быть перенаправлены прямому объекту автоматически без шаблона.

Ответ 1

Я, кажется, наткнулся на решение:

import mock

class A(object):
    def meth(self, a):
        return a
a = A()
ma = mock.Mock(wraps=a)

Кажется, работает нормально для функций, методов и свойств, но не для атрибутов класса или экземпляра.

Смотрите документацию.

Ответ 3

Вы можете использовать простую функцию для итерации всего метода и настройки вашего макета

import inspect 

def spy_mock(instance):
    members = inspect.getmembers(instance, inspect.ismethod)
    attrs = {'%s.side_effect' % k:v for k,v in members}
    return mock.Mock(**attrs)

server.active_attr = spy_mock(server.active_attr)

Ответ 4

Вот как издеваются только datetime.date.today(), передавая остальную часть datetime и datetime datetime звонков на datetime и datetime модуля:

from unittest import mock, TestCase

import foo_module

class FooTest(TestCase):

    @mock.patch(f'{foo_module.__name__}.datetime', wraps=datetime)
    def test_something(self, mock_datetime):
        # mock only datetime.date.today()
        mock_datetime.date.today.return_value = datetime.date(2019, 3, 15)
        # other calls to datetime functions will be forwarded to original datetime

foo_module импортирует datetime и использует много других функций datetime кроме date.today.