在我的previous问题中,我问过如何在课堂上模拟一个包裹requests.get
的课程。如果我只调用requests.get
一次,则提供的answer效果很好。然而,事实证明我的课程比我的榜样更复杂。
我的课程两次拨打request.get
。在初始化之后,因为它会返回API端点,该端点返回我需要在实际请求中使用的API值,以及在我进行.fetch
调用时。
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()
现在,事实证明我需要创建两个模拟响应。一个用于初始化,一个用于.fetch
。使用上一个答案中的代码:
@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
如何为request.get
的这两个单独调用创建单独的响应?
答案 0 :(得分:3)
您可以将iterable分配给模拟对象的side_effects
属性;每次调用mock时,它都会返回iterable的下一个项目。
fake_responses = [Mock(), Mock()]
fake_responses[0].json.return_value = ...
fake_responses[1].json.return_value = ...
fake_get.side_effects = fake_responses
答案 1 :(得分:1)
看起来上一个答案是使用“side_effects”而不是“side_effect”。这就是你在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})
或者你可以像这样实现它:
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})
另请查看此库以帮助您:https://github.com/getsentry/responses