J'écris une application qui effectue des opérations REST en utilisant bibliothèque de requêtes de Kenneth Reitz et j'ai du mal à trouver une belle façon de tester ces applications, car les demandes fournissent ses via des méthodes au niveau du module.
Ce que je veux, c'est la capacité de synthétiser la conversation entre les deux parties; fournir une série d'assertions et de réponses aux demandes.
Si vous utilisez spécifiquement des requêtes, essayez httmock . C'est merveilleusement simple et élégant:
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?'
Si vous voulez quelque chose de plus générique (par exemple pour se moquer de n'importe quelle bibliothèque faisant des appels http), optez pour httpretty .
Presque aussi élégant:
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 est beaucoup plus riche en fonctionnalités - il propose également un code d'état moqueur, des réponses en streaming, des réponses tournantes, des réponses dynamiques (avec rappel).
Il est en fait un peu étrange que la bibliothèque ait une page blanche sur les tests unitaires des utilisateurs finaux, tout en visant la convivialité et la facilité d'utilisation. Il existe cependant une bibliothèque facile à utiliser par Dropbox, sans surprise appelée responses
. Voici son billet d'introduction . Il indique qu'ils n'ont pas réussi à utiliser httpretty
, sans indiquer la raison de l'échec, et a écrit une bibliothèque avec une API similaire.
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)
Vous pouvez utiliser une bibliothèque de simulation telle que Mocker pour intercepter les appels à la bibliothèque de requêtes et renvoyer les résultats spécifiés.
Comme exemple très simple, considérez cette classe qui utilise la bibliothèque de requêtes:
class MyReq(object):
def doSomething(self):
r = requests.get('https://api.github.com', auth=('user', 'pass'))
return r.headers['content-type']
Voici un test unitaire qui intercepte l'appel à requests.get
et renvoie un résultat spécifié pour le test:
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 __== '__main__':
unittest.main()
Lorsque j'exécute ce test unitaire, j'obtiens le résultat suivant:
.
----------------------------------------------------------------------
Ran 1 test in 0.004s
OK
en utilisant moqueur comme dans la réponse de 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()
Pour la bibliothèque de demandes, cela intercepterait la demande par méthode et point de terminaison que vous atteignez et remplacerait le .json () sur la réponse par le json_string transmis.
Il manque request-mock .
De leur page:
>>> import requests >>> import requests_mock
En tant que gestionnaire de contexte:
>>> with requests_mock.mock() as m: ... m.get('http://test.com', text='data') ... requests.get('http://test.com').text ... 'data'
Ou en tant que décorateur:
>>> @requests_mock.mock() ... def test_func(m): ... m.get('http://test.com', text='data') ... return requests.get('http://test.com').text ... >>> test_func() 'data'