我想编写一些测试用例,以在isinstance(obj,request.Response)逻辑中练习 object_check 。在我创建模拟数据作为requests.post的返回值之后。模拟数据的类型始终是Mock类。这样,我该如何重写模拟数据,以便模拟数据可以成为请求的类型。这样我就可以练习第d = obj.json()
行了吗?
from unittest.mock import patch, Mock
import unittest
import requests
from requests.exceptions import HTTPError
import pytest
def object_check(obj):
if isinstance(obj, bytes):
d = ujson.decode(obj.decode())
elif isinstance(obj, requests.Response):
d = obj.json()
else:
raise ValueError('invalid type')
return d
def service_post(params):
"""
trivial function that does a GET request
against google, checks the status of the
result and returns the raw content
"""
url = "https://www.iamdomain.com"
params = {'number': 1234, 'user_id': 1, 'name': 'john'}
resp = requests.post(url, data=params)
return object_check(resp)
@patch.object(requests, 'post')
def test_service_post(mock_request_post):
data = {'number': 0000, 'user_id': 0, 'name': 'john'}
def res():
r = Mock()
r.status_code.return_value = 200
r.json.return_value = data
return r
mock_request_post.return_value = res()
assert data == service_post(data)
答案 0 :(得分:4)
您可以这样做:
@patch.object(requests, 'post')
def test_service_post(mock_request_post):
data = {'number': 0000, 'user_id': 0, 'name': 'john'}
def res():
r = requests.Response()
r.status_code = 200
def json_func():
return data
r.json = json_func
return r
mock_request_post.return_value = res()
assert data == service_post(data)
然后当我在本地运行该测试时,该测试就通过了。 请注意,模拟是一种迷你气味。
我曾经是Mock
的忠实拥护者。但是,随着我成长为一名开发人员,我确实在努力避免这种情况。它可能会诱使您进行一些非常糟糕的设计,并且它们可能真的很难维护(尤其是因为您正在修改Mock
来保存返回值)。 Mock
还会造成一种错误的安全感(即使Web服务发生巨大变化,您的测试也会继续通过,因此您可能会在产品中大放异彩)。我认为您在这里确实不需要它。两种选择:
pickle
序列化(保存)该响应,然后存储到磁盘(将其保存在测试套件中)。然后让您的单元测试读回它并使用实际的响应对象。您仍然需要在patch
上使用requests.post
,但是至少返回值将为您排列,并且您不必随着需求/应用程序的增长而添加或修改它们。patch
:只需在测试中执行POST并检查响应即可。当然,这可能很慢,并且只有在您有互联网的情况下才可以使用。而且您会得到愚蠢的纯粹主义者,他们会告诉您不要在单元测试中这样做。如果您遇到这些纯粹的人之一,也许可以将其转移到集成测试中。但是,认真地说,没有什么可以替代您在生产中实际要做的事情。这样做的好处是,如果Web服务发生更改,那么您将立即了解它并可以修复您的代码。缺点是它可能会减慢您的测试套件的速度,并且它可能是不可靠的测试(如果Web服务关闭,则您的测试将失败...但是知道这一点实际上可能会很好)。我建议如果Web服务不稳定(即易于更改),请使用选项2。否则,请使用选项1。或者对单元测试进行{Mock
和patch
的某种组合,并在集成测试中点击该服务)。只有你可以决定!
HTH,祝你好运!
答案 1 :(得分:1)
在实例化模拟时使用spec
参数:
>>> from unittest.mock import Mock
>>> from requests import Response
>>> m = Mock(spec=Response)
>>> m.__class__
requests.models.Response
>>> isinstance(m, Response)
True
还要注意,r.status_code.return_value = 200
不能用于指定范围;而是直接设置值:
r.status_code = 200
答案 2 :(得分:1)
如果要模拟text
或content
@property值,请在PropertyMock
周围使用text
@patch.object(requests, 'post')
def test_service_post(mock_request_post):
data = {'number': 0000, 'user_id': 0, 'name': 'john'}
def res():
r = requests.Response()
r.status_code = 200
type(r).text = mock.PropertyMock(return_value=my_text) # property mock
def json_func():
return data
r.json = json_func
return r
mock_request_post.return_value = res()
assert data == service_post(data)