Подклассы MagicMock в питоне
У меня есть класс, который мне нужно патчить, который работает примерно так
class Foo(object):
def __init__(self, query):
self._query = query
def do_stuff(self):
# do stuff with self._query
Как бы я создал такой класс для Foo, чтобы
foo = MockFoo(query)
foo.do_stuff()
возвращает фиктивный результат, но все же с учетом данных, переданных для query
, Я думал о подклассе MagicMock
как это
class MockFoo(MagicMock):
def __init__(self, query, *args, **kwargs):
super(MagicMock, self).__init__(*args, **kwargs)
self._query
def do_stuff(self):
mock_result = self._query * 10
return MagicMock(return_value=mock_result)
но я не могу понять, как подать заявку patch
использовать MockFoo
вместо MagicMock
в реальном TestCase. Мне нужно уметь написать тест, похожий на этот.
with patch('x.Foo') as mock_foo:
# run test code
self.assertTrue(mock_foo.called)
self.assertEqual(mock_foo.wait.return_value, 20)
Я знаю, я могу просто использовать простой MagicMock
с autospec=True
или что-то и переопределить возвращаемые значения для каждого из методов, но было бы неплохо иметь фиктивный класс, который я могу просто использовать для замены производственного класса за один раз. Ключевым битом является необходимость доступа к переменной-члену self._query
в имитирующих методах, при этом инициализируя его в конструкторе (как в производственном классе).
1 ответ
О вашей базовой вопрос ответ new_callable
параметр в patch
:
with patch('x.Foo', new_callable=MockFoo) as mock_foo:
# run test code
self.assertTrue(mock_foo.called)
self.assertEqual(mock_foo.wait.return_value, 20)
Если вам нужно добавить аргумент MockFoo
вызов init учитывает, что каждый аргумент не используется в patch
будет вставлен в макет конструктора (MockFoo
в твоем случае).
Если вам нужна оболочка вашего производственного класса, возможно, вы ищете не в том месте: макет - не оболочка.
Когда вы что-то издеваетесь, вы на самом деле не хотите знать, как работает ваш имитатор, а просто как его использует код и как ваш код реагирует на смоделированные объекты.