2017-04-07 7 views
0

J'écris un ensemble d'outils pour tester le comportement d'un serveur HTTP personnalisé: qu'il s'agisse de définir les codes de réponse appropriés, les champs d'en-tête, etc. J'utilise pytest pour écrire tests.py.test: Comment générer des tests à partir d'appareils

L'objectif est de faire des demandes à plusieurs ressources, puis d'évaluer la réponse dans plusieurs tests: chaque test doit tester un seul aspect de la réponse HTTP. Cependant, toutes les réponses ne sont pas testées avec chaque test et vice-versa. Pour éviter d'envoyer la même requête HTTP plusieurs fois et de réutiliser les messages de réponses HTTP, je pense à utiliser les fixtures de pytest, et pour exécuter les mêmes tests sur différentes réponses HTTP, je voudrais utiliser les capacités de test de pytest. demandes d'importation à l'importation pytest

def pytest_generate_tests(metafunc): 
    funcarglist = metafunc.cls.params[metafunc.function.__name__] 
    argnames = sorted(funcarglist[0]) 
    metafunc.parametrize(argnames, [[funcargs[name] for name in argnames] 
            for funcargs in funcarglist]) 


class TestHTTP(object): 
    @pytest.fixture(scope="class") 
    def get_root(self, request): 
     return requests.get("http://test.com") 

    @pytest.fixture(scope="class") 
    def get_missing(self, request): 
     return requests.get("http://test.com/not-there") 

    def test_status_code(self, response, code): 
     assert response.status_code == code 

    def test_header_value(self, response, field, value): 
     assert response.headers[field] == value 

    params = { 
     'test_status_code': [dict(response=get_root, code=200), 
          dict(response=get_missing, code=404), ], 
     'test_header_value': [dict(response=get_root, field="content-type", value="text/html"), 
           dict(response=get_missing, field="content-type", value="text/html"), ], 
    } 

Le problème semble être dans la définition des params: dict(response=get_root, code=200) et définitions similaires ne se rendent pas compte, je voudrais lier sur l'appareil et sur la référence de fonction réelle.

Lorsque l'exécution des tests, je reçois ce genre d'erreurs:

________________________________________________ TestHTTP.test_header_value [type de contenu response0-text/html] _________________________________________________

self = <ev-question.TestHTTP object at 0x7fec8ce33d30>, response = <function TestHTTP.get_root at 0x7fec8ce8aa60>, field = 'content-type', value = 'text/html' 

    def test_header_value(self, response, field, value): 
>  assert response.headers[field] == value 
E  AttributeError: 'function' object has no attribute 'headers' 

test_server.py:32: AttributeError 

Comment puis-je convaincre le pytest de prendre la valeur de l'appareil au lieu de la fonction?

Répondre

1

Pas besoin de générer des tests de fixtues, juste et paramétrez votre appareil écrire des tests réguliers pour les valeurs qu'il retourne:

import pytest 
import requests 


should_work = [ 
    { 
     "url": "http://test.com", 
     "code": 200, 
     "fields": {"content-type": "text/html"} 
    }, 
] 

should_fail = [ 
    { 
     "url": "http://test.com/not-there", 
     "code": 404, 
     "fields": {"content-type": "text/html"} 
    }, 
] 

should_all = should_work + should_fail 


def response(request): 
    retval = dict(request.param) # {"url": ..., "code": ... } 
    retval['response'] = requests.get(request.param['url']) 
    return retval # {"reponse": ..., "url": ..., "code": ... } 


# One fixture for working requests 
response_work = pytest.fixture(scope="module", params=should_work)(response) 
# One fixture for failing requests 
response_fail = pytest.fixture(scope="module", params=should_fail)(response) 
# One fixture for all requests 
response_all = pytest.fixture(scope="module", params=should_all)(response) 


# This test only requests failing fixture data 
def test_status_code(response_fail): 
    assert response_fail['response'].status_code == response_fail['code'] 


# This test all requests fixture data 
@pytest.mark.parametrize("field", ["content-type"]) 
def test_header_content_type(response_all, field): 
    assert response_all['response'].headers[field] == response_all['fields'][field] 
+0

Merci, Nils. Cependant, ce code exécutera tous les tests sur tous les appareils, ce qui n'est pas ce que je désire. Je voudrais spécifier quels tests et quels appareils doivent être combinés. Pour l'argument, imaginez que vous ne voulez pas vérifier le code de retour sur une demande normale, seulement sur celui qui devrait retourner 404. En outre, je veux que chaque test ne vérifie qu'un aspect de la réponse, c'est-à-dire exécuter une seule assertion. Donc, si un en-tête est manquant, je devrais obtenir une erreur pour cet en-tête seulement, alors que pour les autres, les tests devraient passer. – David

+0

Je viens de me rendre compte, je pourrais sauter vérifier avec 'key in response' pour voir si l'objet' response' a une 'key', et si oui, je peux' pytest.skip() 'it. – David

+0

Pourquoi ne pas tester la valeur de retour de chaque demande? Le traitement moins spécial de certaines conditions, moins vous êtes susceptible de faire des erreurs. –