Mock vs MagicMock

Мое понимание заключается в том, что MagicMock - это надмножество Mock, которое автоматически делает "магические методы", таким образом, легко обеспечивая поддержку списков, итераций и т.д.... Тогда в чем причина обычного Mock? Разве это не просто урезанная версия MagicMock, которую можно практически игнорировать? Знает ли класс Mock какие-либо трюки, недоступные в MagicMock?

Ответ 1

В чем причина обычного Mock?

Макет автора, Майкл Фоор, обратился к очень похожим вопросом в Pycon 2011 (31:00):

Q: Почему MagicMock сделал отдельную вещь, а не просто сворачивал эту способность в макетный объект по умолчанию?

A: Один разумный ответ заключается в том, что способ MagicMock заключается в том, что он предварительно сконфигурирует все эти методы протокола, создавая новые Mocks и установив их, поэтому, если каждый новый макет создал кучу новых макетов и установите их как протокольные методы, а затем все эти методы протокола создал кучу более mocks и установил их в своих методах протокола, у вас бесконечная рекурсия...

Что делать, если вы хотите получить доступ к вашему макету в качестве объекта-контейнера как ошибка - вы не хотите, чтобы это сработало? Если каждый макет автоматически получил каждый метод протокола, тогда становится намного сложнее сделать что. Кроме того, MagicMock делает некоторые из этих предварительных настроек для вас, установив возвращаемые значения, которые могут быть неприемлемыми, поэтому я подумал было бы лучше иметь это удобство, у которого есть все предварительно сконфигурированы и доступны для вас, но вы также можете взять обычный mock object и просто настроить магические методы, которые вы хотите использовать...

Простой ответ: просто используйте MagicMock везде, если поведение, которое вы хотите.

Ответ 2

С Mock вы можете издеваться над магическими методами, но вы должны определить их. MagicMock имеет "стандартные реализации большинства магических методов". ,

Если вам не нужно тестировать какие-либо магические методы, Mock подходит и не вносит много посторонних вещей в ваши тесты. Если вам нужно протестировать множество магических методов, MagicMock сэкономит вам время.

Ответ 3

Для начала, MagicMock является подклассом Mock.

class MagicMock(MagicMixin, Mock)

В результате MagicMock предоставляет все, что предоставляет Mock, и многое другое. Вместо того, чтобы думать о том, что Mock является урезанной версией MagicMock, подумайте о MagicMock как расширенной версии Mock. Это должно ответить на ваши вопросы о том, почему Mock существует и что дает Mock в дополнение к MagicMock.

Во-вторых, MagicMock предоставляет стандартные реализации многих/самых магических методов, в то время как Mock этого не делает. См. здесь для получения дополнительной информации о предоставляемых магических методах.

Некоторые примеры предоставленных магических методов:

>>> int(Mock())
TypeError: int() argument must be a string or a number, not 'Mock'
>>> int(MagicMock())
1
>>> len(Mock())
TypeError: object of type 'Mock' has no len()
>>> len(MagicMock())
0

И те, которые могут быть не такими интуитивными (по крайней мере, не интуитивными для меня):

>>> with MagicMock():
...     print 'hello world'
...
hello world
>>> MagicMock()[1]
<MagicMock name='mock.__getitem__()' id='4385349968'>

Вы можете "увидеть" методы, добавленные в MagicMock, поскольку эти методы вызывают в первый раз:

>>> magic1 = MagicMock()
>>> dir(magic1)
['assert_any_call', 'assert_called_once_with', ...]
>>> int(magic1)
1
>>> dir(magic1)
['__int__', 'assert_any_call', 'assert_called_once_with', ...]
>>> len(magic1)
0
>>> dir(magic1)
['__int__', '__len__', 'assert_any_call', 'assert_called_once_with', ...]

Итак, почему бы не использовать MagicMock все время?

Вопрос к вам: вы в порядке с реализациями магического метода по умолчанию? Например, это нормально для mocked_object[1], чтобы не ошибка? Вы в порядке с любыми непредвиденными последствиями из-за того, что реализация магического метода уже существует?

Если ответ на эти вопросы - "да", тогда идите и используйте MagicMock. В противном случае, придерживайтесь Mock.

Ответ 4

Вот что говорится в официальной документации Python:

В большинстве этих примеров классы Mock и MagicMock являются взаимозаменяемыми. Поскольку MagicMock является более способным классом, он делает разумным использование по умолчанию.

Ответ 5

Я обнаружил еще один конкретный случай, когда простой Mock может оказаться более полезным, чем MagicMock:

In [1]: from unittest.mock import Mock, MagicMock, ANY
In [2]: mock = Mock()
In [3]: magic = MagicMock()
In [4]: mock.foo == ANY
Out[4]: True
In [5]: magic.foo == ANY
Out[5]: False

Это может быть полезно, например, для сравнения почти каждого ключа между двумя словарями, где некоторое значение вычисляется с помощью макета.

Это будет действительно, если вы используете Mock:


self.assertDictEqual(my_dict, {
  'hello': 'world',
  'another': ANY
})

в то время как он вызовет MagicMock AssertionError если вы использовали MagicMock