将参数传递给 side_effect 函数以在 unittest.mock 中进行修补

Pass parameter to side_effect function for patching in unittest.mock

我在测试中使用 unittest.mock 中的 patch 来更改远程 API 调用的行为。

我有三个不同的函数,return 三个不同的 json 文件代表要从 API 中 return 编辑的模拟数据。对于每个模拟 api 调用,我将 side_effect 设置为这些函数之一。此模式不是 DRY,但我不知道如何将参数传递给 side_effect 函数。

三个 mock 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_effectmock_call(1) 而不是 mock_call_1)。

unittest docs,我看到:

side_effect: A function to be called whenever the Mock is called. See the side_effect attribute. Useful for raising exceptions or dynamically changing return values. The function is called with the same arguments as the mock, and unless it returns DEFAULT, the return value of this function is used as the return value.

我看到传递给 side_effect 的函数采用与 mock 相同的参数,但我仍然不确定如何最好地使用 mock 来完成此操作。我最终会想要添加更多测试用例,所以我不想硬编码不同的 mock_api_call 函数。

我认为最简单的方法是将 side_effect 设置为 returns 一个函数。

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,它会按预期运行。

使用 lambda 函数:

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()