关于python:将参数传递给side_effect函数,以便在unittest.mock中进行修补

Pass parameter to side_effect function for patching in unittest.mock

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

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

三个模拟api调用函数看起来像这样:

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

这是我的考试

1
2
3
4
5
6
7
8
9
10
11
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)。

从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函数进行硬编码。


使用lambda函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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()

我认为最简单的方法是将side_effect设置为返回函数的函数。

1
2
3
4
5
6
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,它将按预期运行。