Модуль тестирования приложения python, использующего библиотеку запросов
Я пишу приложение, которое выполняет операции REST с помощью Kenneth Reitz запрашивает библиотеку, и я изо всех сил стараюсь найти хороший способ unit test эти приложения, потому что запросы предоставляют свои методы с помощью методов уровня модуля.
То, что я хочу, - это способность синтезировать разговор между двумя сторонами; предоставить ряд утверждений и ответов запросов.
Ответы
Ответ 1
Если вы используете специально запросы, попробуйте httmock. Это чудесно просто и элегантно:
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-вызовы), перейдите к httpretty.
Почти так же элегантно:
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 гораздо более функциональный - он предлагает также издевательский код состояния, потоковые ответы, вращающиеся ответы, динамические ответы (с обратным вызовом).
Ответ 2
Вы можете использовать насмешливую библиотеку, такую как Mocker, чтобы перехватить вызовы в библиотеке запросов и вернуть указанные результаты.
В качестве очень простого примера рассмотрим этот класс, который использует библиотеку запросов:
class MyReq(object):
def doSomething(self):
r = requests.get('https://api.github.com', auth=('user', 'pass'))
return r.headers['content-type']
Здесь unit test, который перехватывает вызов requests.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()
Когда я запускаю этот unit test, я получаю следующий результат:
.
----------------------------------------------------------------------
Ran 1 test in 0.004s
OK
Ответ 3
На самом деле немного странно, что в библиотеке есть пустая страница об тестировании модулей конечного пользователя, ориентируясь на удобство использования и простоту использования. Тем не менее, простая в использовании библиотека Dropbox, неудивительно называется responses
. Вот его вступительный пост. В нем говорится, что они не использовали httpretty, не указав причины сбоя и написав библиотеку с похожим 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)
Ответ 4
используя mocker, как в ответе srgerg:
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()
Для библиотеки запросов это приведет к перехвату запроса методом и конечной точкой, которые вы нажимаете, и замените .json() на ответ с переданной json_string.
Ответ 5
Отсутствие этих ответов request-mock.
На странице:
>>> import requests
>>> import requests_mock
Как менеджер контекста:
>>> 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'