Пропустить до содержимого

Как использовать unittest.mock в Python?

[

Понимание библиотеки Python Mock

Автор: Алекс Ронкильо

Table of Contents

  • Введение
  • Библиотека Python Mock
  • Мок-объект
    • Ленивые атрибуты и методы
    • Утверждения и проверки
    • Управление возвращаемым значением мок-объекта
    • Управление побочными эффектами мок-объекта
    • Конфигурирование мок-объекта
  • Функция patch()
    • patch() как декоратор
    • patch() как менеджер контекста
    • Замена атрибутов объекта
    • Где применять patch()
  • Часто возникающие проблемы
    • Изменение интерфейсов объектов и опечатки
    • Изменение внешних зависимостей
  • Избегание проблем при помощи спецификаций
  • Заключение

Введение

При написании надежного кода тесты являются неотъемлемой частью, так как они проверяют правильность, надежность и эффективность кода. Однако ценность ваших тестов зависит от того, насколько хорошо они демонстрируют эти критерии. Сложные логические выражения и непредсказуемые зависимости могут затруднить написание ценных тестов. Библиотека мок-объектов unittest.mock в Python может помочь вам преодолеть эти трудности.

В конце этой статьи вы сможете:

  • Создавать мок-объекты в Python с использованием Mock
  • Проверять, что объекты используются так, как вы задумывали
  • Изучать данные об использовании, сохраненные в ваших мок-объектах
  • Конфигурировать некоторые аспекты ваших мок-объектов
  • Заменять настоящие объекты на мок-объекты с помощью функции patch()
  • Избегать распространенных проблем, связанных с мокированием в Python

Вначале мы рассмотрим, что такое мокирование и как оно поможет вам улучшить ваши тесты.

Что такое мокирование?

Мок-объект заменяет и имитирует реальный объект в среде тестирования. Он является мощным инструментом для улучшения качества ваших тестов.

Одна из причин использования мок-объектов в Python - контроль поведения вашего кода во время тестирования.

Например, если ваш код выполняет HTTP-запросы к внешним службам, то ваши тесты будут работать предсказуемо только в том случае, если службы будут работать так, как вы ожидаете. Иногда временное изменение поведения этих внешних сервисов может вызвать проблемы в тестовом наборе.

Поэтому лучше всего тестировать код в контролируемой среде. Замена фактического запроса на мок-объект позволит вам симулировать сбои и успешные ответы внешних сервисов предсказуемым образом.

Иногда бывает сложно протестировать определенные части вашего кода. К таким областям относятся блоки except и условные операторы if, которые трудно удовлетворить. Использование мок-объектов в Python поможет вам контролировать путь выполнения вашего кода, чтобы достичь этих областей и увеличить охват вашего кода.

Библиотека Python Mock

Python предоставляет библиотеку unittest.mock, которая позволяет вам создавать мок-объекты и легко управлять их поведением. Библиотека unittest.mock может быть использована вместе с модулем unittest для написания эффективных тестов, включая модульное тестирование и тестирование интеграции.

Мок-объект

Мок-объект, созданный с помощью класса Mock из библиотеки unittest.mock, представляет собой пустой объект, который имитирует поведение реального объекта. Вы можете настраивать его, чтобы он вел себя так, как вам нужно, во время выполнения тестов.

Давайте рассмотрим некоторые важные аспекты мок-объекта, включая ленивые атрибуты и методы, утверждения и проверки, управление возвращаемым значением и побочными эффектами мок-объекта, а также конфигурирование мок-объекта.

Ленивые атрибуты и методы

Ленивые атрибуты и методы могут быть полезными при создании мок-объектов. Они позволяют вам легко имитировать поведение сложных объектов. Библиотека unittest.mock в Python предоставляет специальные методы, такие как side_effect и return_value, для управления поведением мок-объекта.

Вот пример:

from unittest.mock import Mock
def foo():
return 42
mock = Mock()
mock.foo.return_value = 10
mock.bar.side_effect = [Exception("Error 1"), Exception("Error 2")]
print(mock.foo()) # Вывод: 10
print(mock.bar()) # Вывод: Exception("Error 1")
print(mock.bar()) # Вывод: Exception("Error 2")
print(mock.foo()) # Вывод: 10

Утверждения и проверки

Библиотека unittest.mock предоставляет функции для утверждений и проверок, чтобы проверить, что мок-объект используется так, как вы задумывали.

Например, вы можете проверить, что метод вызывается определенное количество раз:

from unittest.mock import Mock
def foo():
return 42
mock = Mock()
mock.foo.return_value = 10
mock.foo()
mock.foo()
mock.foo()
mock.foo.assert_called() # Проверка вызова
mock.foo.assert_called_once() # Проверка однократного вызова
mock.foo.assert_called_with() # Проверка вызова с определенными аргументами
mock.foo.assert_any_call() # Проверка любого вызова с определенными аргументами
mock.foo.assert_called_once_with() # Проверка однократного вызова с определенными аргументами
mock.foo.assert_called_with(42) # Проверка вызова с определенными аргументами

Управление возвращаемым значением мок-объекта

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

from unittest.mock import Mock
def foo():
return 42
mock = Mock()
mock.foo.return_value = 10
print(mock.foo()) # Вывод: 10

Управление побочными эффектами мок-объекта

Побочные эффекты мок-объекта - это действия, выполняемые при вызове метода мок-объекта. Вы можете использовать атрибут side_effect для задания побочных эффектов.

Вот пример:

from unittest.mock import Mock
def foo():
return 42
mock = Mock()
mock.foo.side_effect = [10, 20, 30]
print(mock.foo()) # Вывод: 10
print(mock.foo()) # Вывод: 20
print(mock.foo()) # Вывод: 30

Конфигурирование мок-объекта

Вы можете настраивать различные аспекты мок-объекта с помощью специальных функций библиотеки unittest.mock. Например, вы можете настроить поведение вызовов метода, задать атрибуты мок-объекта и многое другое.

Вот пример:

from unittest.mock import Mock
def foo():
return 42
mock = Mock()
mock.foo.side_effect = [10, 20, 30]
mock.foo.return_value = 100
mock.foo.attribute = "test"
print(mock.foo()) # Вывод: 10
print(mock.foo()) # Вывод: 20
print(mock.foo()) # Вывод: 30
print(mock.foo()) # Вывод: 100
print(mock.foo.attribute) # Вывод: "test"

Функция patch()

Функция patch() является еще одним способом использования мок-объектов в Python. Она позволяет вам временно заменить какой-либо объект или атрибут на мок-объект в определенном контексте.

Функция patch() может использоваться как декоратор или как менеджер контекста. Она также может заменять атрибуты объекта и предоставляет возможность выбора места для замены.

Вот примеры использования функции patch():

from unittest.mock import patch
def foo():
return 42
with patch("module.function", return_value=10) as mock:
print(module.function()) # Вывод: 10
@patch("module.function", return_value=10)
def test_function(mock_function):
print(mock_function()) # Вывод: 10
test_function()
@patch.object(Module, "method", return_value=100)
def test_method(mock_method):
print(Module.method()) # Вывод: 100
test_method()

Часто возникающие проблемы

При использовании мок-объектов могут возникать некоторые распространенные проблемы. Например, изменения в интерфейсах объектов или опечатки могут привести к некорректной работе ваших тестов.

Однако с помощью спецификаций можно избежать многих таких проблем. Спецификации позволяют вам задавать ожидаемое поведение мок-объектов и контролировать их использование.

Вот пример использования спецификаций:

from unittest.mock import Mock, create_autospec
class MyClass:
def add(self, a, b):
return a + b
mock = create_autospec(MyClass)
mock.add.return_value = 100
print(mock.add(10, 20)) # Вывод: 100
print(mock.add(10, 20, 30)) # Вызовет ошибку, так как количество аргументов не соответствует спецификации

Заключение

Библиотека Python Mock предоставляет множество инструментов для создания мок-объектов и управления ими во время тестирования. Она поможет вам написать более эффективные тесты, увеличить покрытие кода и избежать распространенных проблем, связанных с мокированием.

Если вы хотите узнать больше о том, как использовать библиотеку Python Mock, рекомендуется пройти связанный видеокурс “Улучшение ваших тестов с использованием библиотеки мок-объектов в Python”.