2012-03-04 3 views
49

Я пишу приложение, которое выполняет операции REST с использованием requests library Kenneth Reitz, и я изо всех сил пытаюсь найти хороший способ для модульного тестирования этих приложений, поскольку запросы предоставляют его методы с помощью модуля- уровня.Модуль тестирования приложения python, использующего библиотеку запросов

То, что я хочу, это способность синтезировать разговор между двумя сторонами; предоставить ряд утверждений и ответов на запрос.

+2

Так что вам нужно, чтобы дразнить из остального сервер? – kgr

+0

Почему это делает unittest непригодным? Проверьте, как библиотека выполняет собственные модульные тесты; может предложить идеи. –

+1

FWIW, библиотека Requests проводит собственные тесты с использованием живых URL-адресов (github.com, собственный домен авторов и т. Д.). – Raumkraut

ответ

21

Вы можете использовать насмешливую библиотеку, такую ​​как Mocker, чтобы перехватить вызовы библиотеки запросов и вернуть указанные результаты.

В качестве простого примера рассмотрим этот класс, который использует библиотеку запросов:

class MyReq(object): 
    def doSomething(self): 
     r = requests.get('https://api.github.com', auth=('user', 'pass')) 
     return r.headers['content-type'] 

Вот тестовый модуль, который перехватывает вызов 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() 

Когда я запускаю этот модульный тест, я получаю следующий результат:

. 
---------------------------------------------------------------------- 
Ran 1 test in 0.004s 

OK 
2

использованием насмешник, как в ответ 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 прошел в

.
38

Если вы используете специально запросы, попробуйте 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 гораздо более навороченный - он предлагает также насмешливый код состояния, потоковый ответы, вращаясь ответами, динамические характеристики (с обратным вызовом).

+0

Эта вещь httpretty прямо из этого мира, спасибо! – mccc

19

На самом деле немного странно, что в библиотеке есть пустая страница об тестировании модулей конечного пользователя, ориентируясь на удобство использования и простоту использования. Тем не менее, есть простая в использовании библиотека Dropbox, неудивительно называемая responses. Вот его intro post. В нем говорится, что они не смогли использовать 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) 
+0

Обновлен URL-адрес для 'ответов' [** intro post **] (http://cra.mr/2014/05/20/mocking-requests-with-responses) –

0

Отсутствует из этих ответов requests-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' 
+0

Есть ли у вас какие-либо знания о том, как сделать это работать с '' pytest''? Я попробовал точный пример, который вы цитируете. Ref .: https://stackoverflow.com/questions/47703748/why-does-the-simplest-requests-mock-example-fail-with-pytest –

+0

Если я правильно помню, я использовал декоратор. И я думаю, что это также работало с pytest. – Unapiedra

+0

Я сделал это с декораторами, но он появляется (в моей системе), что он противоречит некоторым другим аргументам, поэтому мне пришлось передать аргумент kw в Mocker, как указано в [docs] (https: // request- mock.readthedocs.io/en/latest/mocker.html#decorator). Не уверен, что это связано с pytest, но ошибка, пришедшая к упомянутым светильникам. Спасибо, что вернулись к проблеме. –

Смежные вопросы