New*_*Guy 5 python unit-testing mocking python-2.7
在我之前的问题中,我询问了如何模拟包含requests.get在我的班级中的班级。如果我只打电话一次,提供的答案效果很好requests.get。然而,事实证明我的课程比我做的例子更复杂。
我的班级打了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()
Run Code Online (Sandbox Code Playgroud)
现在,事实证明我需要创建两个模拟响应。一种用于初始化,一种用于.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
Run Code Online (Sandbox Code Playgroud)
如何为这两个单独的调用创建单独的响应request.get?
看起来之前的答案是使用“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})
Run Code Online (Sandbox Code Playgroud)
或者,您可以像这样实现它:
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})
Run Code Online (Sandbox Code Playgroud)
还可以查看此库以帮助您:https : //github.com/getsentry/responses
您可以side_effects为模拟对象的属性分配一个可迭代对象;每次调用模拟时,它都会返回可迭代对象的下一项。
fake_responses = [Mock(), Mock()]
fake_responses[0].json.return_value = ...
fake_responses[1].json.return_value = ...
fake_get.side_effects = fake_responses
Run Code Online (Sandbox Code Playgroud)