I'm using patch
from unittest.mock
to change the behavior of a remote API call in my test.
I have three different functions that return three different json
files that represent the mock data to be returned from the API. For each mock api call, I am setting side_effect
to be one of these functions. This pattern isn't DRY, but I don't know how to pass a parameter to a side_effect
function.
The three mock api call functions look like this:
def mock_api_call_1():
with open('path/to/mock_1.json') as f:
mock_data = json.load(f)
return mock_data
Here's my test
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)
How can I refactor this code to be able to pass a parameter to the side_effect
(mock_call(1)
instead of mock_call_1
).
From the unittest docs, I see that:
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.
I see that the function passed to side_effect
takes the same arguments as the mock, but I'm still not sure how best to use mock to accomplish this. I'll eventually want to add more test cases, so I don't want to be hard-coding different mock_api_call
functions.
Use a lambda function:
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()