Python Django单元测试和模拟请求模块
我是Mock新手,正在为此函数编写单元测试:Python Django单元测试和模拟请求模块,python,unit-testing,mocking,python-requests,Python,Unit Testing,Mocking,Python Requests,我是Mock新手,正在为此函数编写单元测试: # utils.py import requests def some_function(user): payload = {'Email': user.email} url = 'http://api.example.com' response = requests.get(url, params=payload) if response.status_code == 200:
# utils.py
import requests
def some_function(user):
payload = {'Email': user.email}
url = 'http://api.example.com'
response = requests.get(url, params=payload)
if response.status_code == 200:
return response.json()
else:
return None
我使用库作为单元测试的一部分,并且很难模拟response.json()
来返回json结构。下面是我的单元测试:
# tests.py
from .utils import some_function
class UtilsTestCase(unittest.TestCase):
def test_some_function(self):
with patch('utils.requests') as mock_requests:
mock_requests.get.return_value.status_code = 200
mock_requests.get.return_value.content = '{"UserId":"123456"}'
results = some_function(self.user)
self.assertEqual(results['UserId'], '123456')
在阅读文档后,我尝试了多种不同模拟设置的组合,但运气不佳。如果我在单元测试中打印结果
,它总是显示以下内容,而不是我想要的json数据结构:
<MagicMock name=u'requests.get().json().__getitem__().__getitem__()' id='30315152'>
思考我做错了什么?补丁
json
方法,而不是内容
。(内容
未用于某些功能
)
试试下面的代码
import unittest
from mock import Mock, patch
import utils
class UtilsTestCase(unittest.TestCase):
def test_some_function(self):
user = self.user = Mock()
user.email = 'user@example.com'
with patch('utils.requests') as mock_requests:
mock_requests.get.return_value = mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"UserId":"123456"}
results = utils.some_function(self.user)
self.assertEqual(results['UserId'], '123456')
我喜欢使用的另一种更易于重用的模式是在单元测试的
设置
方法中启动补丁程序。检查是否使用预期参数调用了模拟请求也很重要:
class UtilsTestCase(TestCase):
def setUp(self):
self.user = Mock(id=123, email='foo@bar.com')
patcher = patch('utils.requests.get')
self.mock_response = Mock(status_code=200)
self.mock_response.raise_for_status.return_value = None
self.mock_response.json.return_value = {'UserId': self.user.id}
self.mock_request = patcher.start()
self.mock_request.return_value = self.mock_response
def tearDown(self):
self.mock_request.stop()
def test_request(self):
results = utils.some_function(self.user)
self.assertEqual(results['UserId'], 123)
self.mock_request.assert_called_once_with(
'http://api.example.com'
payload={'Email': self.user.email},
)
def test_bad_request(self):
# override defaults and reassign
self.mock_response.status_code = 500
self.mock_request.return_value = self.mock_response
results = utils.some_function(self.user)
self.assertEqual(results, None)
self.mock_request.assert_called_once_with(
'http://api.example.com'
payload={'Email': user.email},
)
我认为另一种方式更清晰、更直截了当:
import unittest
from mock import Mock, patch
import utils
class UtilsTestCase(unittest.TestCase):
def test_some_function(self):
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"UserId": "123456"}
with patch('utils.requests.get') as mock_requests:
results = utils.some_function(self.user)
self.assertEqual(results['UserId'], '123456')
非常感谢你的回答。它现在正如我所希望的那样工作。我将向您添加的另一个断言测试单元测试将是确保使用预期参数调用request.get方法。类似于,
mock\u get.assert\u调用了带有('http://api.example.com“,payload={'Email':self.user.Email}
。这确保库代码使用预期参数进行请求调用,这与测试库代码的返回值(模拟)一样重要。