Библиотека unittest mock

Posted by     "Георгий Кузора" on Friday, May 5, 2023

Варианты использования

Модуль mock можно использовать в следующих случаях.

Проверить вызывается ли метод внутри другого метода

Возникают ситуации, когда необходимо проверить был ли метод вызван при работе другого метода. Mock объекты имеют несколько методов для того чтобы определить вызвался ли метод объекта. А также какие параметры он при этом использовал.

Предположим что есть класс с двумя методами. При этом в первом методе вызывается второй метод с атрибутами 1, 2, 3.

class ProductionClass():
    def method_1(self):
        self.method_2(1, 2, 3)

    def method_2(self, a, b, c):
     pass

Нужно проверить что второй метод действительно вызывается.

object = ProductionClass()
object.method_2 = MagicMock()
object.method_1()
object.method_2.assert_called_once_with(1, 2, 3)

Для выполнения проверки:

  1. Создаем объект класса.
  2. Заменяем второй метод mock объектом.
  3. Вызываем первый метод
  4. Mock объект записывает действия которые были над ним выполнены.
  5. Мы можем проверить что второй метод вызывался с заданными атрибутами ровно один раз.

Задать функции нужное возвращаемое значение

Можно не только проверять какие действия были совершены над mock объектом. Mock объект может возвращать указанное пользователем значение. Применим эту возможность, чтобы получить нужное для теста значение внутри тестируемой функции.

class ProductionClass():
    def method_1(self):
        a = self.method_2()
        return a

    def method_2(self):
     b = external_module.method()
     return b

Проверим что второй метод действительно вызывается в первом, и что первый метод возвращает значение переданное ему вторым методом.

object = ProductionClass()
object.method_2 = MagicMock(return_value=True)
a = object.method_1()
object.method_2.assert_called_once()
assert a

Для выполнения проверки:

  1. Создадим объект объект класса.
  2. Заменим второй метод mock объектом.
  3. Зададим mock объекту возвращаемое значение = True.
  4. Зададим переменной a значение возвращаемое первым методом.
  5. Проверим что второй метод вызван только один раз.
  6. Проверим что метод 1 вернул верное значение.

Проверка как функция реагирует на возникающие side effects

В ходе работы функции возникают side effects. Это события которые не должны возникать по замыслу создателя кода. Они вызывают баги и создают исключения в ходе работы функции.

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

class ProductionClass():
    def method_1(self):
        a = self.method_2()
        return a

    def method_2(self):
     b = external_module.method()
     return b

Проверим как будет реагировать метод один на side effects возникающие при работе метода два.

object = ProductionClass()
object.method_2 = MagicMock()
object.method_2.side_effect = [5, 4, 3, 2, 1, KeyError('foo')]
a = object.method_1()
assert a == 5
a = object.method_1()
assert a == 4
a = object.method_1()
assert a == 3
a = object.method_1()
assert a == 2
a = object.method_1()
assert a == 1
a = object.method_1()
Traceback (most recent call last):
 ...
KeyError: 'foo'
  1. Зададим для mock объекта side effects в виде списка значений.
  2. При каждом вызове функции mock объект итерирует над списком значений и возвращает новое значение из списка.
  3. При вызове объекта с исключение, возникнет исключение при работе метода один.