Класс Mock модуля unittest.mock в Python
- Что такое Mock-класс Unittest в Python?
- Когда использовать mock?
- Зачем нужны?
- Пример Unittest Mock в Python
Что такое Mock-класс Unittest в Python?
Моки имитируют поведение реальных объектов. Чтобы протестировать объект, который изолированно зависит от других объектов, вы используете Mock-объекты, чтобы имитировать реальные объекты.
Чтобы имитировать объекты, вы используете модуль unittest.mock. Модуль unittest.mock предоставляет класс Mock, который позволяет имитировать другие объекты.
Он также предоставляет класс MagicMock, который является подклассом класса Mock. Помимо методов и свойств класса Mock, класс MagicMock содержит реализации всех методов dunder, например __str__ и __repr__.
См. следующий пример:
from unittest.mock import Mock # create a new mock object mock = Mock() # mock the api function mock.api.return_value = { 'id': 1, 'message': 'hello' } # call the api function print(mock.api())
Выход:
{'id': 1, 'message': 'hello'}
Как это работает.
- Сначала импортируйте класс Mock из модуля unittest.mock:
from unittest.mock import Mock
- Во-вторых, создайте новый экземпляр класса Mock:
mock = Mock()
- В-третьих, измените функцию api() и присвойте ее возвращаемое значение словарю:
mock.api.return_value = { 'id': 1, 'message': 'hello' }
Наконец, вызовите api() из mock объекта. Он вернет присвоенное значение:
print(mock.api())
В этом примере у нас есть два мок-объекта: mock и mock.api.
Давайте добавим в программу оператор print(), чтобы увидеть, как он работает:
from unittest.mock import Mock # create a new mock object mock = Mock() print(mock) # mock the api function mock.api.return_value = { 'id': 1, 'message': 'hello' } print(mock.api) # call the api print(mock.api())
Выход:
<Mock id='1830094470496'> <Mock name='mock.api' id='1830100086416'> {'id': 1, 'message': 'hello'}
В выводе показаны два Mock-объекта.
Короче говоря, если вы назначите свойство, которого нет в объекте Mock, Python вернет новый Mock-объект. Из-за этой динамики вы можете использовать класс Mock для имитации любых объектов, которые захотите.
Когда использовать mock?
Вот случаи, в которых вы можете рассмотреть возможность использования mock:
- Системные вызовы
- Сеть
- Операция ввода-вывода
- Часы и время, часовые пояса
- Или другие случаи, результаты которых непредсказуемы.
Зачем нужны?
Ниже приведены преимущества mock-объектов:
- Ускоряют тест
- Исключают внешнее дублирование
- Сделают непредсказуемые результаты предсказуемыми.
Пример Unittest Mock в Python
Предположим, у вас есть модуль odometer.py:
from random import randint def speed(): return randint(40, 120) def alert(): s = speed() if s < 60 or s > 100: return True return False
В модуле Sensor.py:
- Функция Speed() возвращает текущую скорость транспортного средства. Она возвращает случайное значение от 40 до 120. В реальном мире функция считывает данные с одометра.
- Функция alert() возвращает true, если текущая скорость ниже 60 км/ч и выше 120 км/ч. Функция alert() использует функцию Speed() для получения текущей скорости.
Функцию alert() будет сложно протестировать, поскольку значение, возвращаемое функцией Speed(), варьируется. Чтобы решить эту проблему, вы можете использовать класс Mock.
Следующее создает тестовый модуль test_odometer.py, который тестирует функцию alert():
test_alert_normal(test_odometer.TestOdometer) ... ok ---------------------------------------------------------------------- Ran 1 test in 0.000s OK
Как это работает.
- Сначала назначьте объект Mock функции odometer.speed:
odometer.speed = Mock()
- Во-вторых, установите возвращаемое значение функции Speed() равным 70:
odometer.speed.return_value = 70
- В-третьих, вызовите функцию alert() и проверьте, возвращает ли она False. Функция alert() вызовет Mock-объект вместо фактической функции Speed().
На следующем рисунке показано, как тест работает с Mock-объектом:
Запустите тест:
python -m unittest test_odometer.py -v
Выход:
test_alert_normal(test_odometer.TestOdometer) ... ok ---------------------------------------------------------------------- Ran 1 test in 0.000s OK
Следующее добавляет тестовые примеры с превышением и понижением скорости:
import unittest from unittest.mock import Mock import odometer class TestOdometer(unittest.TestCase): def test_alert_normal(self): odometer.speed = Mock() odometer.speed.return_value = 70 self.assertFalse(odometer.alert()) def test_alert_overspeed(self): odometer.speed = Mock() odometer.speed.return_value = 100 self.assertFalse(odometer.alert()) def test_alert_underspeed(self): odometer.speed = Mock() odometer.speed.return_value = 59 self.assertTrue(odometer.alert())
Запустите тест:
python -m unittest test_odometer.py -v
Выход:
test_alert_normal(test_odometer.TestOdometer) ... ok test_alert_overspeed(test_odometer.TestOdometer) ... ok test_alert_underspeed(test_odometer.TestOdometer) ... ok ---------------------------------------------------------------------- Ran 3 tests in 0.001s OK