Передайте параметр функции side_effect для исправления в unittest.mock

Я использую patch из unittest.mock, чтобы изменить поведение удаленного вызова API в своем тесте.

У меня есть три разные функции, которые возвращают три разных файла json, которые представляют фиктивные данные, которые должны быть возвращены из API. Для каждого фиктивного вызова API я устанавливаю side_effect в качестве одной из этих функций. Этот шаблон не СУХОЙ, но я не знаю, как передать параметр функции side_effect.

Три фиктивные функции вызова API выглядят следующим образом:

def mock_api_call_1():
    with open('path/to/mock_1.json') as f:
        mock_data = json.load(f)
    return mock_data

вот мой тест

class MyTest(TestCase):

    def test_api(self):

        with patch('mymodule.utils.api_call', side_effect=mock_api_call_1):
            do_crud_operations()
            self.assertEqual(MyModel.objects.all().count(), 10)

        with patch('mymodule.utils.api_call', side_effect=mock_api_call_2):
            do_crud_operations()
            self.assertEqual(MyModel.objects.all().count(), 11)

Как я могу реорганизовать этот код, чтобы иметь возможность передавать параметр в side_effect (mock_call(1) вместо mock_call_1).

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

side_effect: функция, которая будет вызываться всякий раз, когда вызывается Mock. См. атрибут side_effect. Полезно для создания исключений или динамического изменения возвращаемых значений. Функция вызывается с теми же аргументами, что и макет, и, если она не возвращает значение DEFAULT, возвращаемое значение этой функции используется в качестве возвращаемого значения.

Я вижу, что функция, переданная side_effect, принимает те же аргументы, что и макет, но я все еще не уверен, как лучше всего использовать макет для достижения этой цели. Со временем я захочу добавить больше тестовых случаев, поэтому я не хочу жестко кодировать разные mock_api_call функции.


person briancaffey    schedule 21.01.2019    source источник


Ответы (2)


Используйте лямбда-функцию:

from unittest import TestCase, main
from unittest.mock import Mock, patch
import sys

def mock_api_call(x):
    print(x)

class MyTest(TestCase):
    def test_api(self):
        with patch('sys.exit',
                    side_effect=lambda x: mock_api_call(x)) as m:
            m(0)
            sys.exit(0)

            m(1)
            sys.exit(1)


if __name__ == '__main__':
    main()
person progmatico    schedule 21.01.2019

Я думаю, что самый простой способ сделать это — установить side_effect на функцию, которая возвращает функцию.

def mock_call(num):
    def wrapper():
        with open("path/to/mock_{num}.json") as f:
            data = json.load(f)
        return data
    return wrapper

Теперь я могу передать mock_call(1) в side_effect, и он будет вести себя так, как ожидалось.

person briancaffey    schedule 21.01.2019