Класс 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() для получения текущей скорости.

Пример использования класса Mock в Python

Функцию 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-объектом:

Тестирование с Mock-объектом в Python

Запустите тест:

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
Похожие посты
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *