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

一个人想着一个人 提交于 2019-12-21 22:59:21

问题


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.


回答1:


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)



回答2:


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



来源:https://stackoverflow.com/questions/35732487/how-do-i-mock-a-method-that-uses-requests-get-in-my-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!