Чем `MagicMock` отличается от обычного `Mock` в `unittest.mock`?

`MagicMock` является подклассом `Mock` и имеет дополнительную магию:
  • Он реализует большинство magic методов Python (например, `__len__`, `__getitem__`, `__add__` и т.д.).
  • При вызове magic методов, он возвращает другие `MagicMock` объекты, позволяя более гибко и реалистично эмулировать поведение объектов.
  • `Mock` же просто возвращает `Mock` при любом вызове атрибута или метода, если не было настроено другое поведение.
То есть, `MagicMock` удобнее, когда вам нужно мокать объекты, использующие magic методы.

В Python's unittest.mock, и Mock, и MagicMock используются для создания объектов-заглушек, которые можно использовать для замены зависимостей в ваших тестах. Основное различие между ними заключается в том, как они обрабатывают "магические" методы (также известные как dunder methods) Python, такие как __str__, __len__, __add__ и т.д.

Mock:

  • Mock является более базовым классом. Он ведет себя как обычный объект Python.
  • По умолчанию, если вы попытаетесь вызвать магический метод на объекте Mock, то получите исключение AttributeError, если этот метод не был специально настроен для возврата чего-либо.
  • Это означает, что для того, чтобы Mock корректно имитировал объект, поддерживающий магические методы, вам нужно явно настроить эти методы, указав для них возвращаемые значения или побочные эффекты.

MagicMock:

  • MagicMock наследуется от Mock, но автоматически предоставляет реализации для большинства магических методов.
  • Когда вызывается магический метод на MagicMock объекте, он возвращает другой MagicMock объект по умолчанию. Это означает, что вызовы магических методов "просто работают" без необходимости явной настройки.
  • Это делает MagicMock более удобным и менее подверженным ошибкам в сценариях, где вам нужно имитировать объекты, которые интенсивно используют магические методы. Например, имитация контейнера, который поддерживает операции сравнения, сложения или определения длины.

Пример:

Допустим, вы хотите имитировать объект, который поддерживает операцию сложения (__add__). С Mock вам нужно будет: my_mock = Mock(); my_mock.__add__ = Mock(return_value=5). С MagicMock это уже настроено по умолчанию.

Когда использовать что?

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

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

0