Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock two separate responses to same function in same test

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?

like image 920
NewGuy Avatar asked Mar 02 '16 03:03

NewGuy


People also ask

How do you mock the same method twice in jest?

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.

Can I mock functions with specific arguments using jest?

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.

How do you mock a function?

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.


2 Answers

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
like image 162
chepner Avatar answered Nov 02 '22 22:11

chepner


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

like image 41
Adam Raudonis Avatar answered Nov 03 '22 00:11

Adam Raudonis