2017-08-28 4 views
3

Ich bin ein Anfänger zu pytest in Python und versuchen, Testfälle für die folgende Methode zu schreiben, die die Benutzeradresse erhalten, wenn die richtige ID übergeben wird, steigt benutzerdefinierte Fehler BadId.Python Pytest zum Testen der Anfragen und Antwort

def get_user_info(id: str, host='127.0.0.1', port=3000) -> str: 
    uri = 'http://{}:{}/users/{}'.format(host,port,id) 
    result = Requests.get(uri).json() 
    address = result.get('user',{}).get('address',None) 
    if address: 
     return address 
    else: 
     raise BadId 

Kann mir jemand dabei helfen und können Sie mir auch vorschlagen, was sind die besten Ressourcen für das Lernen von Pytest? TIA

+0

auch: für die Nachfrage nach Ressourcen wird als Off-Topic SO, aber hier ist, was ich gelernt habe "Pytest": [link] (https://www.youtube.com/watch?v=l32bsaIDoWk&list=PLeo1K3hjS3utzQYDNRNluzqJqpMXx6hHu) [link] (https://www.youtube.com/watch? v = UPanUFVFfzY) [link] (https://www.youtube.com/watch?v=k99HS HQDsi4). –

+0

Vielen Dank @RickTeachey für das Aufzeigen des Fehlers und der Ressourcen. –

Antwort

2

Ihr Testschema könnte in etwa so aussehen.

Zuerst schlage ich vor, eine Vorrichtung zu erstellen, die in Ihren verschiedenen Methodentests verwendet werden kann. Das Fixture richtet eine Instanz Ihrer Klasse ein, die in Ihren Tests verwendet werden soll, anstatt die Instanz im Test selbst zu erstellen. Durch die Trennung von Aufgaben auf diese Weise können Sie Ihre Tests robuster und leichter lesbar machen.

from my_package import MyClass 
import pytest 

@pytest.fixture 
def a_test_object(): 
    return MyClass() 

Sie können das Testobjekt zu Ihrer Reihe von Verfahren Prüfungen bestehen:

def test_something(a_test_object): 
    # do the test 

Allerdings, wenn Ihr Prüfobjekt einiger Ressourcen während der Installation erfordert (wie zum Beispiel eine Verbindung, eine Datenbank, eine Datei, usw. usw.), können Sie es stattdessen vortäuschen, um die Einrichtung der Ressourcen für den Test zu vermeiden. Eine nützliche Information dazu finden Sie unter this talk.

Übrigens: Wenn Sie mehrere verschiedene Zustände des benutzerdefinierten Objekts, das in Ihrem Gerät erstellt wird, testen müssen, müssen Sie Ihr Gerät parametrieren. Dies ist ein etwas kompliziertes Thema, aber die Dokumentation explains fixture parametrization very clearly.

Die andere Sache, die Sie tun müssen, ist sicherzustellen, dass alle .get Anrufe an Requests abgefangen werden. Dies ist wichtig, da es ermöglicht, dass Ihre Tests ohne Internetverbindung ausgeführt werden, und stellt sicher, dass sie nicht als Ergebnis einer fehlerhaften Verbindung ausfallen. Dies ist nicht das, was Sie testen möchten.

Sie können Requests.get mit dem monkeypatch feature von pytest abfangen. Alles, was erforderlich ist, ist, monkeypatch als einen Eingabeparameter für die Testregimenfunktionen aufzunehmen.

Sie können eine andere Vorrichtung verwenden, um dies zu erreichen. Es könnte wie folgt aussehen:

import Requests 
import pytest 

@pytest.fixture 
def patched_requests(monkeypatch): 
    # store a reference to the old get method 
    old_get = Requests.get 
    def mocked_get(uri, *args, **kwargs): 
     '''A method replacing Requests.get 
     Returns either a mocked response object (with json method) 
     or the default response object if the uri doesn't match 
     one of those that have been supplied. 
     ''' 
     _, id = uri.split('/users/', 1) 
     try: 
      # attempt to get the correct mocked json method 
      json = dict(
      with_address1 = lambda: {'user': {'address': 123}}, 
      with_address2 = lambda: {'user': {'address': 456}}, 
      no_address = lambda: {'user': {}}, 
      no_user = lambda: {}, 
      )[id] 
     except KeyError: 
      # fall back to default behavior 
      obj = old_get(uri, *args, **kwargs) 
     else: 
      # create a mocked requests object 
      mock = type('MockedReq',(), {})() 
      # assign mocked json to requests.json 
      mock.json = json 
      # assign obj to mock 
      obj = mock 
     return obj 
    # finally, patch Requests.get with patched version 
    monkeypatch.setattr(Requests, 'get', mocked_get) 

Das sieht kompliziert, bis Sie verstehen, was geschieht: wir einfach ein paar verspottet json Objekte gemacht haben (durch Wörterbücher dargestellt) mit vorher festgelegten Benutzer-IDs und Adressen. Die gepatchte Version von Requests.get gibt einfach ein Objekt vom Typ MockedReq - mit der entsprechenden abgespeckten Methode .json() zurück, wenn seine ID angefordert wird.

Beachten Sie, dass Requests nur in Tests gepatcht werden, die tatsächlich die oben Halterung verwenden, z.B .:

def test_something(patched_requests): 
    # use patched Requests.get 

Jeder Test, der nicht patched_requests als Eingabeparameter nicht verwendet wird nicht die gepatchte Version verwenden.

Beachten Sie auch, dass Sie innerhalb des Tests selbst monkeypatch Requests, aber ich schlage vor, es separat zu tun. Wenn Sie andere Teile der Anforderungs-API verwenden, müssen Sie diese möglicherweise ebenfalls anpassen.All diese Dinge getrennt zu halten, wird oft einfacher zu verstehen sein, als wenn man sie in den Test mit einbezieht.

Schreiben Sie Ihre verschiedenen Methodentests als nächstes. Sie benötigen für jeden Aspekt Ihrer Methode einen anderen Test. Mit anderen Worten, Sie schreiben in der Regel einen anderen Test für die Instanz, in der Ihre Methode erfolgreich ist, und eine andere für den Test, wenn sie fehlschlägt.

Zuerst testen wir den Methodenerfolg mit ein paar Testfällen.

@pytest.mark.parametrize('id, result', [ 
    ('with_address1', 123), 
    ('with_address2', 456), 
]) 
def test_get_user_info_success(patched_requests, a_test_object, id, result): 
    address = a_test_object.get_user_info(id) 
    assert address == result 

Als nächstes können wir für die Anhebung der BadId Ausnahme testen Sie die with pytest.raises Funktion. Beachten Sie, dass, da eine Ausnahme ausgelöst wird, kein result Eingangsparameter für die Testfunktion vorhanden ist.

@pytest.mark.parametrize('id', [ 
    'no_address', 
    'no_user', 
]) 
def test_get_user_info_failure(patched_requests, a_test_object, id): 
    from my_package import BadId 
    with pytest.raises(BadId): 
     address = a_test_object.get_user_info(id) 

Wie in meinem Kommentar geschrieben, hier sind auch einige zusätzliche Ressourcen, die Sie mehr über pytest lernen zu helfen:

link

link