In my previous question, I asked how to Mock a class that wraps requests.get
in my class. The answer provided works well, if I am only calling requests.get
once. However, it turns out my class is more complicated than I made my example.
My class calls request.get
twice. Once at initialization, because it hits an API end point that returns API values I need to use in my actual request, and once when I make my .fetch
call.
import requests
class ExampleAPI(object):
def __init__(self):
self.important_tokens = requests.get(url_to_tokens)['tokens']
def fetch(self, url, params=None, key=None, token=None, **kwargs):
return requests.get(url, params=self.important_tokens).json()
Now, it turns out I need to create two mock responses. One for the initialization and one for the .fetch
. Using the code from the previous answer:
@patch('mymodule.requests.get')
def test_fetch(self, fake_get):
expected = {"result": "True"}
fake_get.return_value.json.return_value = expected
e = ExampleAPI() # This needs one set of mocked responses
self.assertEqual(e.fetch('http://my.api.url.example.com'), expected) # This needs a second set
How can I create seperate responses for these two seperate calls to request.get
?
You can use jest. mock (line 4) to mock the lang dependency. In the example above, the mock module has a current field which is set to a mock function. You want to test both branches of hello, so you use mockReturnValueOnce to make the mock function return "GL" in the first invocation, and "EN" in the second one.
Jest is a great tool for testing the stack; jest-when allows you to expect specific arguments for mock functions which enables you to write more robust unit tests of modules with many dependencies.
There are two ways to mock functions: Either by creating a mock function to use in test code, or writing a manual mock to override a module dependency.
You can assign an iterable to the side_effects
attribute of a mock object; each time the mock is called, it returns the next item of the iterable.
fake_responses = [Mock(), Mock()]
fake_responses[0].json.return_value = ...
fake_responses[1].json.return_value = ...
fake_get.side_effects = fake_responses
Looks like the previous answer was using "side_effects" instead of "side_effect". This is how you can do that in Python 3:
import requests
import unittest
from unittest import mock
from unittest.mock import Mock
class Tests(unittest.TestCase):
@mock.patch('requests.get')
def test_post_price_band(self, fake_get):
fake_responses = [Mock(), Mock()]
fake_responses[0].json.return_value = {"a": 1}
fake_responses[1].json.return_value = {"b": 2}
fake_get.side_effect = fake_responses
r1 = requests.get('https://www.api.com').json()
self.assertEqual(r1, {"a": 1})
r2 = requests.get('https://www.api.com').json()
self.assertEqual(r2, {"b": 2})
Alternatively you could implement it like so:
class MockResponse:
def __init__(self, json_data, status_code=requests.codes.ok):
self.json_data = json_data
self.status_code = status_code
def json(self):
return self.json_data
class Tests(unittest.TestCase):
@mock.patch('requests.get')
def test_post_price_band(self, fake_get):
fake_get.side_effect = [
MockResponse({"a": 1}),
MockResponse({"b": 2})
]
r1 = requests.get('https://www.api.com')
self.assertEqual(r1.status_code, requests.codes.ok)
self.assertEqual(r1.json(), {"a": 1})
r2 = requests.get('https://www.api.com')
self.assertEqual(r2.status_code, requests.codes.ok)
self.assertEqual(r2.json(), {"b": 2})
Also check out this library to help you: https://github.com/getsentry/responses
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With