单元测试使用请求库的python应用程序
我正在使用Kenneth Reitz编写一个执行REST操作的应用程序,我正在努力找到一种很好的方法来对这些应用程序进行单元测试,因为请求通过模块级方法提供其方法单元测试使用请求库的python应用程序,python,unit-testing,testing,mocking,python-requests,Python,Unit Testing,Testing,Mocking,Python Requests,我正在使用Kenneth Reitz编写一个执行REST操作的应用程序,我正在努力找到一种很好的方法来对这些应用程序进行单元测试,因为请求通过模块级方法提供其方法 我想要的是综合双方对话的能力;提供一系列请求断言和响应。您可以使用模拟库,例如拦截对请求库的调用并返回指定结果 作为一个非常简单的例子,考虑使用请求库的类: class MyReq(object): def doSomething(self): r = requests.get('https://api.git
我想要的是综合双方对话的能力;提供一系列请求断言和响应。您可以使用模拟库,例如拦截对请求库的调用并返回指定结果
作为一个非常简单的例子,考虑使用请求库的类:
class MyReq(object):
def doSomething(self):
r = requests.get('https://api.github.com', auth=('user', 'pass'))
return r.headers['content-type']
下面是一个单元测试,它拦截对请求的调用。get
并返回指定的测试结果:
import unittest
import requests
import myreq
from mocker import Mocker, MockerTestCase
class MyReqTests(MockerTestCase):
def testSomething(self):
# Create a mock result for the requests.get call
result = self.mocker.mock()
result.headers
self.mocker.result({'content-type': 'mytest/pass'})
# Use mocker to intercept the call to requests.get
myget = self.mocker.replace("requests.get")
myget('https://api.github.com', auth=('user', 'pass'))
self.mocker.result(result)
self.mocker.replay()
# Now execute my code
r = myreq.MyReq()
v = r.doSomething()
# and verify the results
self.assertEqual(v, 'mytest/pass')
self.mocker.verify()
if __name__ == '__main__':
unittest.main()
当我运行此单元测试时,我得到以下结果:
.
----------------------------------------------------------------------
Ran 1 test in 0.004s
OK
使用类似于srgerg回答中的mocker:
def replacer(method, endpoint, json_string):
from mocker import Mocker, ANY, CONTAINS
mocker = Mocker()
result = mocker.mock()
result.json()
mocker.count(1, None)
mocker.result(json_string)
replacement = mocker.replace("requests." + method)
replacement(CONTAINS(endpoint), params=ANY)
self.mocker.result(result)
self.mocker.replay()
对于requests库,这将按要命中的方法和端点拦截请求,并用传入的json_字符串替换响应中的.json() 如果您专门使用请求,请尝试。它非常简单和优雅:
from httmock import urlmatch, HTTMock
import requests
# define matcher:
@urlmatch(netloc=r'(.*\.)?google\.com$')
def google_mock(url, request):
return 'Feeling lucky, punk?'
# open context to patch
with HTTMock(google_mock):
# call requests
r = requests.get('http://google.com/')
print r.content # 'Feeling lucky, punk?'
如果您想要更通用的东西(例如,模拟任何进行http调用的库),请选择
几乎同样优雅:
import requests
import httpretty
@httpretty.activate
def test_one():
# define your patch:
httpretty.register_uri(httpretty.GET, "http://yipit.com/",
body="Find the best daily deals")
# use!
response = requests.get('http://yipit.com')
assert response.text == "Find the best daily deals"
HTTPretty的功能更加丰富——它还提供模拟状态代码、流式响应、旋转响应、动态响应(带有回调)。事实上,该库有一个关于最终用户单元测试的空白页,同时以用户友好性和易用性为目标,这有点奇怪。然而,Dropbox提供了一个易于使用的库,毫不奇怪地称为。这是它的名字。它说他们并没有采用这种方法,但并没有说明失败的原因,并用类似的API编写了一个库
import unittest
import requests
import responses
class TestCase(unittest.TestCase):
@responses.activate
def testExample(self):
responses.add(**{
'method' : responses.GET,
'url' : 'http://example.com/api/123',
'body' : '{"error": "reason"}',
'status' : 404,
'content_type' : 'application/json',
'adding_headers' : {'X-Foo': 'Bar'}
})
response = requests.get('http://example.com/api/123')
self.assertEqual({'error': 'reason'}, response.json())
self.assertEqual(404, response.status_code)
这些答案中缺少的是 从他们的页面: 作为上下文管理器:
>>> with requests_mock.mock() as m:
... m.get('http://test.com', text='data')
... requests.get('http://test.com').text
...
'data'
或者作为一名装饰师:
>>> @requests_mock.mock()
... def test_func(m):
... m.get('http://test.com', text='data')
... return requests.get('http://test.com').text
...
>>> test_func()
'data'
所以您需要模拟REST服务器?为什么这会使unittest不适合?检查库如何进行自己的单元测试;可能会提供ideas.FWIW,请求库使用实时URL(github.com,作者自己的域等)进行自己的测试。httpretty的东西是直接从这个世界出来的,谢谢!您是否知道如何使用
pytest
?我试过了你举的例子。如果我没记错的话,我用的是装饰师。我认为这也适用于pytest。我让它适用于decorators,但(在我的系统上)它似乎与其他参数冲突,因此我必须将kw参数传递给Mocker,如中所述。不确定这是否与pytest有关,但出现的错误提到了fixture。感谢回到这个问题。更新了回复的URL
,有趣的是,因为这是作为一个答案发布的,这个库的作者大卫·克拉默(David Cramer)继续前进,创建了Sentry,并且。这就是为什么在GitHub上它位于getsentry
org下。
>>> @requests_mock.mock()
... def test_func(m):
... m.get('http://test.com', text='data')
... return requests.get('http://test.com').text
...
>>> test_func()
'data'