Ich versuche, eine Klasse zu testen, die einige Hadoop-Webdienste aufruft. Der Code ist so ziemlich in der Form:
method() {
...use Jersey client to create WebResource...
...make request...
...do something with response...
}
zB gibt es eine Methode zum Erstellen eines Verzeichnisses, eine Methode zum Erstellen eines Ordners usw.
Wie kann ich dies testen, da der Code einen externen Webdienst betrifft, über den ich keine Kontrolle habe? Ich könnte versuchen, den Webservice-Client / die Antworten zu verspotten, aber das verstößt gegen die Richtlinie, die ich in letzter Zeit häufig gesehen habe: "Verspotten Sie keine Objekte, die Sie nicht besitzen". Ich könnte eine Dummy-Web-Service-Implementierung einrichten - wäre das noch ein "Unit-Test" oder wäre es dann ein Integrationstest? Ist es einfach nicht möglich, einen Unit-Test auf diesem niedrigen Niveau durchzuführen - wie würde ein TDD-Praktiker damit umgehen?
quelle
Antworten:
Meiner Meinung nach sollten Sie die Webservice-Aufrufe verspotten, wenn dies ein Unit-Test im Gegensatz zu einem Integrationstest ist.
Ihr Komponententest sollte nicht prüfen, ob der externe Webservice funktioniert oder ob Ihre Integration in ihn korrekt ist. Beachten Sie, dass ein Nebeneffekt der Umwandlung Ihres Komponententests in einen Integrationstest darin besteht, dass er wahrscheinlich langsamer abläuft und Sie schnelle Komponententests wünschen, ohne zu dogmatisch zu werden.
Sollte dies auch dazu führen, dass der Unit-Test fehlschlägt, wenn der Webservice vorübergehend nicht verfügbar ist oder nicht ordnungsgemäß funktioniert? Es scheint nicht richtig. Ihr Unit-Test sollte nur aus einem Grund fehlschlagen: wenn der Code in dieser "Unit" einen Fehler enthält.
Der einzige Teil des Codes, der hier relevant ist, ist
...do something with response...
. Verspotte den Rest.quelle
Ich bin nicht einverstanden mit "Verspotten Sie keine Objekte, die Sie nicht besitzen", wenn Sie Unit-Tests durchführen.
Mocks Existenzzweck ist die Tatsache, dass es Module, Bibliotheken und Klassen geben wird, die wir nicht besitzen werden.
Mein Vorschlag für Ihr Szenario ist, den Web-Service-Aufruf zu verspotten.
Richten Sie das Mock so ein, dass es Daten an Ihr Modul zurückgibt.
Stellen Sie sicher, dass Sie alle Szenarien abdecken, z. B. wenn die zurückgegebenen Daten null sind, wenn die zurückgegebenen Daten gültig sind usw.
Und für den Code, den Sie besitzen, müssen Sie als Entwickler sicherstellen, dass der von Ihnen erstellte Code in allen Szenarien die erwartete Leistung erbringt.
quelle
Ich würde für diesen Test so etwas wie EasyMock verwenden. Mocking-Frameworks sind eine ideale Möglichkeit, externe Abhängigkeiten von einer Klasse zu entfernen, und geben Ihnen vollständige Kontrolle über das Ergebnis externer Abhängigkeiten während der Tests. Um Ihr Beispiel ein wenig zu erweitern:
Als Erstes müssen Sie die Logik in Ihrer Klasse extrahieren, in der Sie Jersey verwenden, um eine WebResource abzurufen und den Webdienst in einer separaten Klasse aufzurufen. Wenn Sie ein Interface für diese Klasse erstellen, können Sie einen Mock erstellen, dem Sie dann das Verhalten diktieren können.
Sobald diese Schnittstelle erstellt ist, können Sie mit EasyMock einen Mock erstellen, der ein bestimmtes Objekt gemäß Ihrem Testfall zurückgibt. Das obige Beispiel ist eine Vereinfachung der Strukturierung eines einfachen verspotteten Tests und der Funktionsweise Ihrer Benutzeroberfläche.
Weitere Informationen zum Verspotten von Frameworks finden Sie in dieser Frage . In diesem Beispiel wird auch die Verwendung von Java vorausgesetzt, aber die Spott-Frameworks sind in allen Sprachen verfügbar und obwohl sie unterschiedlich implementiert sind, funktionieren sie im Allgemeinen auf die gleiche Weise
quelle
Mocks sind in diesem Fall akzeptabel, aber Sie brauchen es nicht. Anstelle von Unit-Tests
method()
sollten Sie stattdessen nur den Teil testen, der die Antwort verarbeitet.Extrahieren Sie eine Funktion
ResponseData
(welche Art auch immer geeignet ist) und führen Sie dann die Aktion aus.Anstatt zu verspotten, erstellen Sie jetzt einfach ein ResponseData-Objekt und übergeben es.
Sie können den Aufruf des Dienstes den vollständigen Integrationstests überlassen - dies wird
method()
insgesamt abgedecktquelle
Was ich getan habe und es funktioniert:
3.1 Zunächst werden alle Webservices getestet. Von jeder Maschine aus, auch von Entwicklermaschinen. Dies sind die eigentlichen Webservices, die jedoch in der Entwicklungsumgebung ausgeführt werden. Dies bedeutet, dass Webservices niemals inaktiv sein oder fehlerhafte Werte beantworten können, da sich ansonsten jeder Entwickler beschwert, dass er nicht kompilieren kann.
3.2 Anschließend werden alle applikationsinternen Komponententests durchgeführt. Dies bedeutet, dass alle Webservices mit den gleichen Tests wie in 3.1 verspottet und getestet werden (sie sollten auch bestanden werden, da sonst die Verspottungen falsch sind) und von der realen Anwendung aufgerufen werden, als ob sie tatsächlich verwendet würden. Wenn die Mocks falsch sind, können Sie den Test in 3.1 ausführen und diese (Anforderungs-, Antwort-) Werte in einer HashMap aufzeichnen.
3.3 Dann werden die gleichen Tests wie in 3.2 ausgeführt, diesmal jedoch gegen die echten Webservices, die in der Entwicklungsumgebung ausgeführt werden.
Nachdem all dies abgeschlossen ist, müssen Sie für die reale Produktionsumgebung nur die reale Adresse für jeden Webservice angeben. Hoffentlich erfordert dies nicht zu viele Änderungen in der Konfiguration.
quelle