22 WebAPI – Webdienste testen

WebAPI-Tests zeichnen sich dadurch aus, dass WebAPI-Anfragen generiert und deren Antwort und Verhalten überprüft werden. End-to-End-Testszenarien mit zahlreichen Schritten und Abhängigkeiten sind der Bereich, bei dem QF-Test glänzt. Das bedeutet, dass Sie im Gegensatz zu anderen Testwerkzeugen, mit denen Sie nur eine HTTP-Anfrage senden und die Antwort verifizieren können, mit QF-Test komplexe Tests implementieren können, bei denen der WebAPI-Test nur ein Teil davon ist. Das heißt, Sie können WebAPI-Tests in End-to-End-GUI-Tests und andere Arten der Automatisierung integrieren.

10.0+ Vor Version 10.0 bot QF-Test nur Funktionen zum Testen einfacher HTTP-Abläufe. In Version 10.0 wurden neue Knoten für die Behandlung komplexerer Szenarien eingeführt, insbesondere die Knoten Web-Request, Pre-Request-Handler und Post-Request-Handler ebenso wie Request-Anmeldedaten und Request-Einstellungen. Sie ersetzen die bestehenden Knoten und erweitern die Funktionalität, die für WebAPI-Tests bereitgestellt wird, beträchtlich:

Die Implementierung basiert auf dem Paket "java.net.http" aus dem Standard-JDK. Die API wird durch QF-Test mit einer einfach zu bedienenden grafischen Oberfläche versehen, wobei für Experten auch die Möglichkeit besteht, die Objekte in Skripten direkt anzusprechen.

Hinweis Das WebAPI-Feature benötigt eine Lizenz für QF-Test Web oder für QF-Test Pro.

22.1 Struktur der WebAPI-Tests

Die äußere Struktur der WebAPI-Tests unterscheidet sich nicht von der Struktur von Oberflächentests: Testfälle werden zu Testfallsätzen zusammengefügt, die ihrerseits auf Testsuiten aufgeteilt werden können, die wiederum in einem Projekt liegen können. Prozeduren und Abhängigkeiten sind auch bei WebAPI-Test ausgesprochen hilfreich.

Pre- and Post-request structure
Abbildung 22.1:  Pre- und Post-Request Struktur

Im Web-Request-Knoten kann ein Aufruf der WebAPI in einer grafischen Oberfläche konfiguriert werden.

Die Pre-Request-Handler und Post-Request-Handler-Knoten implementieren eine Reihe von Methoden (Handler) für die Bearbeitung der WebAPI-Daten vor dem Versand des Requests und für die Verifizierung der Response-Daten - oder um Werte aus der erhaltenen Antwort auszulesen. Request-Anmeldedaten and Request-Einstellungen Knoten können in einen Pre-Request-Handler eingefügt werden. Sie bieten eine grafische Oberfläche für die Konfiguration der Anmeldedaten und Web-Client-Einstellungen. Weitergehende Zugriffe auf die API können über Server-Skript-Knoten implementiert werden.

Die Pre- und Post-Request-Sequenzen, die sich innerhalb eines Web-Request-Knotens befinden, gelten nur für diesen. Wenn sie auf höherer Ebene platziert werden, wirkt sich dies auf alle darunterliegenden Web-Request-Knoten aus. Für die Gültigkeit gilt in beiden Fällen: lokal geht über global beziehungsweise innen geht über außen.

Das Protokoll enthält alles, was für die Analyse der Request-Ergebnisse benötigt wird. Außer den Web-Request, Pre-Request-Handler und Post-Request-Handler-Knoten finden Sie spezielle Protokolleinträge für die Daten des tatsächlich verschickten Web-Requests sowie der erhaltenen Antwort, jeweils mit Header und Body.

Pre- and Post-request flow
Abbildung 22.2:  Pre- und Post-Request Ablauf

Im Server-Skript Knoten können Sie die "WebAPI Skripting-API" verwenden, die für alle Skriptsprachen verfügbar ist. Wir empfehlen jedoch Groovy, da es angenehmer beim Zugriff auf JSON-Werte ist und besser mit QF-Test interagiert als die etwas limitierte JavaScript-Engine "Nashorn", welche QF-Test nutzt.

Beispiele finden Sie in der Demo-Testsuite webapi_testing.qft, die über das Menü »Datei«-»Lesezeichen«-»Beispiel-Testsuiten«-»WebAPI Suite« oder über »Hilfe«-»Beispiel-Testsuiten erkunden...« geöffnet werden kann.

22.2 Request-Anmeldedaten

Mit Hilfe des Request-Anmeldedaten-Knotens können Sie die Zugangsdaten für einen einzelnen oder mehrere Web-Request-Knoten konfigurieren und setzen.

Derzeit unterstützt (HTTP authentication schemes):

Bitte kontaktieren Sie support@qfs.de, falls Ihr benötigtes Authentifizierungsschema hier nicht aufgeführt ist.

22.2.1 Alle SSL-Zertifikate akzeptieren

QF-Test akzeptiert alle SSL-Zertifikate. Sie können die Überprüfung von SSL-Zertifikaten aktivieren, indem Sie die Option OPT_WEBREQUEST_TRUST_ALL_SSL auf false setzen.

rc.setOption(Options.OPT_WEBREQUEST_TRUST_ALL_SSL, false)
Beispiel 22.1:  SSL-Zertfikatsprüfung aktivieren

Falls Sie Probleme bei der Verbindung zur zu testenden WebAPI haben, versuchen Sie, QF-Test folgendermaßen zu starten:

qftest -J-Djdk.internal.httpclient.disableHostnameVerification=true
Beispiel 22.2:  Hostname-Verifikation abschalten

Ein im JDK vorhandener Fehler kann es erforderlich machen, QF-Test mit dieser JVM-Property zu starten.

22.3 Request-Einstellungen

Der Request-Einstellungen Knoten unterstützt aktuell:

Zusätzliche Einstellungen können über ein Server-Skript innerhalb des Post-Request-Handler-Knotens festgelegt werden.

22.3.1 Cookies

Cookies können über die Server-Skript-Option OPT_WEBREQUEST_COOKIES aktiviert oder deaktiviert werden. Standardmäßig sind Cookies aktiviert.

rc.setOption(Options.OPT_WEBREQUEST_COOKIES, false)
Beispiel 22.3:  Deaktivieren von Cookies

22.3.2 Proxy

Proxy-Einstellungen können über die Server-Skript-Option OPT_WEBREQUEST_PROXY festgelegt oder überschrieben werden. Standardmäßig ist die Option nicht gesetzt.

rc.setOption(OPT_WEBREQUEST_PROXY, "my.company.proxy:8081")
Beispiel 22.4:  Festlegen eines Proxy-Hosts und Proxy-Ports

22.3.3 Timeouts und Netzwerkfehler

QF-Test wendet auf jeden Web-Request Knoten ein Timeout an. Ist kein knotenspezifisches Wartezeit gesetzt, gilt der globale Standardwert aus Standard-Timeout für HTTP-Request-Knoten (ms) (Werkseinstellung: 20000 ms).

Das Attribut Fehlerstufe bei Zeitüberschreitung und die globale Standardoption Fehlerstufe bei Zeitüberschreitung im HTTP-Request-Knoten steuern, wie Timeouts und Verbindungsfehler behandelt werden. Nicht alle Fehlerbedingungen werden durch diese Einstellung gesteuert:

Antwort-Timeout
Innerhalb des Zeitlimits wurde keine Antwort empfangen. Wird entsprechend der effektiven Fehlerstufe behandelt.
Verbindungs-Timeout
Die TCP-Verbindung konnte innerhalb des im Request-Einstellungen gesetzten Limits nicht hergestellt werden. Wird entsprechend der effektiven Fehlerstufe behandelt, wie ein Antwort-Timeout.
Verbindung abgelehnt
Der Server hat die Verbindung aktiv abgelehnt. Wirft immer eine Exception. Dies ist ein harter Fehler, der nicht durch die Fehlerstufen-Einstellung gesteuert wird.
Sonstige Netzwerkfehler
Unbekannter Hostname, SSL/TLS-Fehler und sonstige E/A-Fehler. Werfen immer eine Exception mit einer beschreibenden Fehlermeldung.

22.4 Body

Dieser Abschnitt enthält Dokumentation zur Bearbeitung des Bodys einer HTTP-Anfrage.

22.4.1 multipart/form-data

Einige Web-APIs erfordern multipart/form-data für das Senden eines zusammengesetzten Bodys. Ein typisches Beispiel besteht aus einer kurzen Texteingabe zusammen mit einer Datei.

Standardbibliothek enthält das Package qfs.webapi. Dort finden Sie die Prozeduren qfs.webapi.body.multipart.addString und qfs.webapi.body.multipart.addFile.

22.5 End-to-End-Szenarien – Geschäftsanwendungslogik

Angenommen, Sie möchten einen Testfall erstellen, der ein End-to-End-Szenario wie zum Beispiel einen Geschäftsprozess oder eine umfangreiche Transaktion abbilden soll. In diesem Fall sollten Vorbereitung, Aufräumen und Fehlerbehandlung für die Testfälle über die Abhängigkeiten in QF-Test implementiert werden. Informationen zum datengetriebenen Testen finden Sie im Kapitel Datentreiber im Handbuch. Für die Konfiguration, Ausführung und Validierung von WebAPI-Anfragen stehen die Pre-Request-Handler und Post-Request-Handler-Sequenzen zur Verfügung.

22.6 Generierung von Single-Request-API-Aufrufen

In diesem Fall fungiert QF-Test als Generator für WebAPI-Requests. Es ist also keine komplexe Testfalllogik erforderlich. Auch hier kann die Abhängigkeit auf oberster Ebene genutzt werden, um allgemeine Vorbereitungen, Aufräumaktionen und Fehlerbehandlung einzurichten.

Durch die Verwendung von Pre-Request-Handler- und Post-Request-Handler-Sequenzen auf oberer Ebene können allgemeine Einstellungen und Validierungen eingerichtet werden.

22.7 HTML-Report

Standardmäßig werden im HTML-Report von QF-Test nur fehlgeschlagene Validierungen gemeldet. Sie können die Protokollierung erfolgreicher Checks über die Option "Checks auflisten" im Dialog "Report erstellen" oder über das Kommandozeilenargument "-report-checks (nur Batchmodus)" erzwingen.

Weitere Informationen zur automatisierten Reporterstellung finden Sie unter "Testausführung im Batchmodus".

22.8 Postman-Migration

Über das Menü »Extras«-»Postman-Collections konvertieren…« wird ein Ordner oder eine einzelne Postman-Sammlung in eine QF-Test Testsuite konvertiert. Die JavaScript-Skripte von Postman werden als Platzhalter in Groovy-Skripten platziert, Sie müssen sie neu schreiben, wenn Sie diese weiterhin benötigen.
Einige zusätzliche Einstellungen, Authentifizierungen oder Metadaten könnten ignoriert werden.

Klicken Sie auf "Convert", um den Dateiauswahldialog zu öffnen. Der Konvertierungsvorgang beginnt unmittelbar nach dem Schließen des Dateiauswahldialogs.

22.9 Importieren einer OpenAPI-Spezifikation

11.0+

QF-Test kann eine Testsuite direkt aus einer OpenAPI-3.x- oder Swagger-2.x-Spezifikationsdatei (JSON- oder YAML-Format) generieren. Das Feature liest die API-Beschreibung und erstellt parametrisierte Prozeduren für jede HTTP-Operation, gruppiert sie nach Tag und generiert - wo möglich - vollständige CRUD-Testfälle automatisch.

Der Import ist verfügbar über »Extras«-»OpenAPI-Spezifikation importieren« .

22.9.1 Was vom OpenAPI-Standard abgedeckt wird

Der Importer verarbeitet die folgenden Elemente eines OpenAPI-3.x-Dokuments:

OpenAPI-Element Verwendung
servers[0].url Basis-URL für alle generierten Anfragen
paths + HTTP-Methoden (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS) Eine Prozedur pro Operation
operationId Prozedurname (Fallback auf <method>_<path>, falls nicht vorhanden)
tags Jeder Tag wird zu einem Package, das verwandte Prozeduren gruppiert
summary / description Wird als Kommentar in die generierte Prozedur eingefügt
Pfadparameter {param} Werden unverändert in der URL beibehalten; eine passende Prozedur-Variable wird hinzugefügt
Pflicht-Abfrageparameter Als Web-Request-Variablen hinzugefügt, immer in der Anfrage enthalten
Optionale Abfrageparameter Als Prozedur-Variablen deklariert; zur Laufzeit nur an den URI angehängt, wenn nicht leer
formExplode-, pipeDelimited-, deepObject-Abfrageparameter-Stile Jeder Stil wird mit dem entsprechenden Pre-Request-Skript behandelt
Request-Body (JSON, XML, Form-kodiert) Wird als typisierter Payload generiert; Felder der obersten Ebene werden zu Prozedur-Variablen
Schema-$ref-Referenzen Werden automatisch aufgelöst - referenzierte Komponentenschemata werden an allen Vorkommen expandiert
Antwort-Statuscodes Am Web-Request gesetzt; QF-Test verifiziert den erwarteten Code automatisch
Antwort-Body (application/json) GET/PUT/PATCH-Prozeduren stellen die vollständige Antwort als Rückgabewert bereit; POST-Prozeduren stellen das Primärschlüsselfeld (z.B. id) bereit
Sicherheitsschemata In jede Prozedur eingefügt: API-Key, Bearer-Token oder Basic-Auth, je nach Angabe in der Spezifikation
PathItem-Parameter Werden mit operationsspezifischen Parametern zusammengeführt (Operation hat Vorrang bei Konflikt)
allOf-Schemata Eigenschaften aller Teilschemata werden zusammengeführt und als einzelnes Objekt behandelt
readOnly-Schema-Eigenschaften Aus allen generierten Request-Bodies ausgeschlossen (JSON, XML, Form-kodiert)
info.description / info.version Als Kommentar zum obersten API-Package hinzugefügt
tags[].description Als Kommentar zum entsprechenden Tag-Package hinzugefügt
OpenAPI-3.2.x-Dateien Werden akzeptiert - das Versionsfeld wird intern vor dem Parsen normalisiert
Swagger-2.0- / OpenAPI-2.0-Dateien Werden vor dem Import automatisch in OpenAPI 3.x konvertiert (siehe "Weitere Hinweise und Einschränkungen")

22.9.2 Struktur der generierten Testsuite

Der Import erstellt eine .qft-Datei mit folgender Struktur:

Packages  "Prozeduren"
  Package  "<API-Titel>"
    Package  "<Tag>"                      ein Package pro OpenAPI-Tag
      Prozedur  "<operationId>"           eine Prozedur pro HTTP-Operation
          Parameter    param1 = ""
                       param2 = "example-default"
          Kommentar    Operationsbeschreibung
                       @param param1  (Required)  integer (int64)
                       @param param2  string, one of: [available, pending, sold]
                       @return        200 OK (Pet {id, name, status})
          Web-Request
                  url          https://host/base/{param1}
                  method       GET | POST | PUT | ...
                  statuscode   200 | 201 | 204 | ...
                  Variablen    Pflicht-Abfrageparameter
                  payload      {"param2": "$(param2)"}
              Pre-Request-Handler  (bei Bedarf)
                  Request-Anmeldedaten   Sicherheits-Anmeldedaten
                  Server-Skript          optionale Abfrage- und Body-Parameter
          Server-Skript                  rc.returnValue(qw.response.json)

Testfallsatz  "<API-Titel>"
  Testfall  "<Tag>"                       ein Testfall pro Tag
      Prozeduraufruf -> <operationId 1>
      Prozeduraufruf -> <operationId 2>
      ...
  Testfall  "<Tag> CRUD"                  ein zusätzlicher Testfall pro erkannter CRUD-Ressource
      Parameter    <pathParam> = ""
                   <bodyFields> = "TestValue"
      CREATE -> READ -> verify -> UPDATE -> re-fetch -> verify -> DELETE
Beispiel 22.5:  Übersicht der generierten Testsuiten-Struktur

22.9.2.1 Parametrisierung von Request-Body-Feldern

Der Importer wendet drei Stufen der Parametrisierung auf Request-Body-Felder an:

Stufe Wann Payload-Form Prozedur-Variable?
Felder der obersten Ebene (Tiefe 1) Immer $(fieldName) Ja - erscheint in der Variablenliste der Prozedur
Tief verschachtelte Felder (Tiefe >= 2) Feld hat einen Schemawert (Beispiel oder Standardwert) ${default:fieldName:schemaValue} Nein - ${default:x:v} löst zur Variable x auf, falls gesetzt, andernfalls Fallback auf v
Tief verschachtelte Felder (Tiefe >= 2) Kein Schemawert verfügbar Literal synthetisierter Wert Nein

Die ${default:name:fallback}-Syntax ist ein eingebautes QF-Test-Feature: Der Ausdruck wertet zur Laufzeit den Wert der Variable name aus oder fallback, wenn die Variable leer oder undefiniert ist. Das bedeutet, dass tief verschachtelte Felder von Anfang an sinnvolle Werte enthalten, aber durch das Deklarieren einer gleichnamigen Variable im Testfall oder Prozeduraufruf überschrieben werden können.

22.9.2.2 Prozedurkommentare und @param / @return Dokumentation

Jede generierte Prozedur enthält einen Kommentarabschnitt mit:

22.9.2.3 Sicherheit

Wenn die Spezifikation Sicherheitsschemata definiert, fügt QF-Test einen Request-Anmeldedaten-Knoten in den Pre-Request-Handler jeder Prozedur ein (API-Key, Bearer-Token oder Basic-Auth, je nach Angabe in der Spezifikation). Ein Kommentarabschnitt an der Wurzel der Suite listet auf, welche Anmeldedaten vor dem Ausführen der Tests konfiguriert werden müssen.

22.9.3 CRUD-Testfälle

Wenn der Importer eine Create-/Read-/Update-/Delete-Operationsgruppe für eine Ressource erkennen kann, generiert er einen in sich geschlossenen Testfall, der:

22.9.4 Vor dem Ausführen der generierten Testsuite

  1. baseUrl aktualisieren. Häufig enthalten die Spezifikationen einen relativen Pfad zum Server.
  2. Anmeldedaten eintragen. Suchen Sie die Variablendefinitionsabschnitte am Anfang der Suite, die die erforderlichen Sicherheitsvariablen (API-Key, Benutzername, Passwort, Token) auflisten, und setzen Sie deren Werte.
  3. Prozedurparameter prüfen. Jede Prozedur hat Standardparameterwerte, die aus den example-Feldern der Spezifikation abgeleitet werden. Passen Sie diese bei Bedarf für Ihre Testumgebung an.
  4. Optionale Parameter prüfen. Variablen für optionale Parameter haben einen Standardwert aus dem Spezifikationsbeispiel oder sind leer, falls keiner angegeben ist. Lassen Sie sie leer, um den Parameter aus der Anfrage wegzulassen, oder füllen Sie sie aus, um ihn einzuschließen.
  5. Einzelne Prozeduren zuerst ausführen, um Konnektivität und Authentifizierung zu bestätigen, und dann die generierten CRUD-Testfälle für End-to-End-Abdeckung ausführen.

22.9.5 Weitere Hinweise und Einschränkungen

22.10 HTTP-Standards und Webdienste

Alle Webdienste und Websites verwenden das Hypertext Transfer Protocol. Es ist eine textbasierte Kommunikation, die aus Anfragen und Antworten besteht. Hier sind die nützlichsten und überraschend kurzen Internetstandards aufgelistet:

Die HTTP-Anfrage besteht aus Headern, URL und optional Payload (Body).

Die folgenden Grafiken veranschaulichen die Struktur einer HTTP-GET-Anfrage und ihrer Antwort. Die Grafiken stammen aus den Entwicklertools des Chrome-Browsers.

Hinweis Bitte beachten Sie, dass die Entwicklertools eines Browsers nicht das beste Mittel zur Analyse von HTTP-Anfragen sind, da Browser Informationen hinzufügen oder zusätzliche Aktionen ausführen, wie z. B. die erneute Anmeldung nach Ablauf einer Sitzung. Verwenden Sie stattdessen einen speziellen WebAPI-Inspektor. Weitere Informationen finden Sie unter Web-API-Inspektor.

Browser send HTTP request
Abbildung 22.3:  Browser HTTP GET

Die Antwort vom Server enthält Antwortcode, Header und optional Nutzlast.

GET response
Abbildung 22.4:  Browser HTTP GET Response

22.10.1 Web-API-Inspektor

Um die Netzwerkkommunikation zu verfolgen, wird ein Proxy benötigt. Installieren oder verwenden Sie die portable Version von mitmproxy. Die Demo-Suite demo/mitmproxy.qft aus der QF-Test Installation enthält eine Abhängigkeit, die Sie für Ihren Test verwenden können. Sie können auch ein beliebiges Proxy-Programm starten und anschließend über die Option Options.OPT_WEBREQUEST_PROXY einen Proxy für den WebAPI-Test einrichten.

22.11 Die Knoten Server-HTTP-Request und Browser-HTTP-Request (Legacy)

Die Knoten Server-HTTP-Request und Browser-HTTP-Request werden aus Gründen der Abwärtskompatibilität weiterhin unterstützt. Für neue Tests empfehlen wir jedoch die Verwendung von Web-Request.

Der Knoten Server-HTTP-Request kann zum Senden beliebiger HTTP-Pakete an einen Host verwendet werden. Er unterstützt die HTTP-Anforderungsmethoden GET, POST, HEAD, PUT, DELETE, TRACE und CONNECT.

Bei Server-HTTP-Request müssen Sie selbst dafür sorgen, die HTTP-Anforderung zu erstellen und die Antworten und/oder Ergebnisse zu überprüfen bzw. zu validieren. Geben Sie alle erforderlichen Daten an den entsprechenden Stellen ein, z. B. Header, Nutzdaten usw. Die Antwortverarbeitung sollte bei Bedarf mithilfe der Variablen, die in der Serverantwort eingetragen werden, erstellt werden.

Beispiele finden Sie in der Beispiel-Testsuite demo/webservices mit dem Namen webservice_testing.qft. Die Beispiele wurden mithilfe eines für Entwicklungszwecke verwendeten HTTP-Proxys erstellt. Ein solcher Proxy ist mitmproxy.