NewGuy
NewGuy

Reputation: 3423

How do I mock a method that uses requests.get in my class?

I'm attempting to create a few unit tests for my class. I want to mock these, so that I don't burn through my API quota running some of these tests. I have multiple test cases that will call the fetch method, and depending on the passed URL I'll get different results back.

My example class looks like this:

import requests
class ExampleAPI(object):
    def fetch(self, url, params=None, key=None, token=None, **kwargs):
        return requests.get(url).json() # Returns a JSON string

The tutorial I'm looking at shows that I can do something like this:

import unittest
from mock import patch

def fake_fetch_test_one(url):
    ...

class TestExampleAPI(unittest.TestCase):
    @patch('mymodule.ExampleAPI.fetch', fake_fetch_test_one)
    def test_fetch(self):
        e = ExampleAPI()
        self.assertEqual(e.fetch('http://my.api.url.example.com'), """{'result': 'True'}""")

When I do this, though, I get an error that says:

TypeError: fake_fetch_test_one() takes exactly 1 argument (3 given)

What is the proper way to mock a requests.get call that is in a method in my class? I'll need the ability to change the mock'd response per test, because different URLs can provide different response types.

Upvotes: 2

Views: 10286

Answers (2)

chepner
chepner

Reputation: 532208

Your fake fetch needs to accept the same arguments as the original:

def fake_fetch(self, url, params=None, key=None, token=None, **kwargs):

Note that it's better to mock just the external interface, which means letting fetch call requests.get (or at least, what it thinks is requests.get):

@patch('mymodule.requests.get')
def test_fetch(self, fake_get):
    # It would probably be better to just construct
    # a valid fake response object whose `json` method
    # would return the right thing, but this is a easier
    # for demonstration purposes. I'm assuming nothing else
    # is done with the response.
    expected = {"result": "True"}
    fake_get.return_value.json.return_value = expected
    e = ExampleAPI()
    self.assertEqual(e.fetch('http://my.api.url.example.com'), expected)

Upvotes: 7

maazza
maazza

Reputation: 7193

from you test method you can monkeypatch your requests module

import unittest

class Mock:
   pass

ExampleAPI.requests = Mock()

def fake_get_test_one(url):
    /*returns fake get json */

ExampleAPI.requests.get= Mock()
ExampleAPI.requests.json = fake_get_test_one

class TestExampleAPI(unittest.TestCase):

    def test_fetch(self):
        e = ExampleAPI()
        self.assertEqual(e.fetch('http://my.api.url.example.com'), """{'result': 'True'}""")

you can setup the patch in each setup() and corresponding teardown() methods of your test class if needed

Upvotes: 0

Related Questions