Testen Sie eine REST-API mit Java

1. Übersicht

Dieses Tutorial konzentriert sich auf die Grundprinzipien und Mechanismen des Testens einer REST-API mit Live-Integrationstests (mit einer JSON-Nutzlast).

Das Hauptziel ist es, eine Einführung in das Testen der grundlegenden Korrektheit der API zu geben - und wir werden für die Beispiele die neueste Version der GitHub REST-API verwenden.

Bei einer internen Anwendung wird diese Art von Tests normalerweise als später Schritt in einem kontinuierlichen Integrationsprozess ausgeführt, wobei die REST-API verwendet wird, nachdem sie bereits bereitgestellt wurde.

Beim Testen einer REST-Ressource gibt es normalerweise einige orthogonale Verantwortlichkeiten, auf die sich die Tests konzentrieren sollten:

  • der HTTP- Antwortcode
  • andere HTTP- Header in der Antwort
  • die Nutzlast (JSON, XML)

Jeder Test sollte sich nur auf eine einzelne Verantwortung konzentrieren und eine einzige Aussage enthalten. Die Konzentration auf eine klare Trennung hat immer Vorteile, aber bei dieser Art von Black-Box-Tests ist dies noch wichtiger, da die allgemeine Tendenz darin besteht, am Anfang komplexe Testszenarien zu schreiben.

Ein weiterer wichtiger Aspekt der Integrationstests ist die Einhaltung des Single Level of Abstraction-Prinzips - die Logik innerhalb eines Tests sollte auf einer hohen Ebene geschrieben werden. Details wie das Erstellen der Anforderung, das Senden der HTTP-Anforderung an den Server, der Umgang mit E / A usw. sollten nicht inline, sondern über Dienstprogrammmethoden erfolgen.

2. Testen des Statuscodes

@Test public void givenUserDoesNotExists_whenUserInfoIsRetrieved_then404IsReceived() throws ClientProtocolException, IOException { // Given String name = RandomStringUtils.randomAlphabetic( 8 ); HttpUriRequest request = new HttpGet( "//api.github.com/users/" + name ); // When HttpResponse httpResponse = HttpClientBuilder.create().build().execute( request ); // Then assertThat( httpResponse.getStatusLine().getStatusCode(), equalTo(HttpStatus.SC_NOT_FOUND)); }

Dies ist ein ziemlich einfacher Test - er überprüft, ob ein grundlegender glücklicher Pfad funktioniert , ohne die Testsuite zu komplex zu gestalten.

Wenn dies aus irgendeinem Grund fehlschlägt, müssen Sie keinen anderen Test für diese URL durchführen, bis dies behoben ist.

3. Testen des Medientyps

@Test public void givenRequestWithNoAcceptHeader_whenRequestIsExecuted_thenDefaultResponseContentTypeIsJson() throws ClientProtocolException, IOException { // Given String jsonMimeType = "application/json"; HttpUriRequest request = new HttpGet( "//api.github.com/users/eugenp" ); // When HttpResponse response = HttpClientBuilder.create().build().execute( request ); // Then String mimeType = ContentType.getOrDefault(response.getEntity()).getMimeType(); assertEquals( jsonMimeType, mimeType ); }

Dadurch wird sichergestellt, dass die Antwort tatsächlich JSON-Daten enthält.

Wie Sie vielleicht bemerkt haben, verfolgen wir eine logische Abfolge von Tests - zuerst den Antwortstatuscode (um sicherzustellen, dass die Anforderung in Ordnung war), dann den Medientyp der Antwort, und erst im nächsten Test werden wir uns den ansehen tatsächliche JSON-Nutzlast.

4. Testen der JSON-Nutzlast

@Test public void givenUserExists_whenUserInformationIsRetrieved_thenRetrievedResourceIsCorrect() throws ClientProtocolException, IOException { // Given HttpUriRequest request = new HttpGet( "//api.github.com/users/eugenp" ); // When HttpResponse response = HttpClientBuilder.create().build().execute( request ); // Then GitHubUser resource = RetrieveUtil.retrieveResourceFromResponse( response, GitHubUser.class); assertThat( "eugenp", Matchers.is( resource.getLogin() ) ); }

In diesem Fall weiß ich JSON die Standarddarstellung von GitHub Ressourcen ist, aber in der Regel, die Content-Type sollten Header der Antwort neben dem getestet werden Accept - Header der Anforderung - der Kunde fragt nach einer bestimmten Art von Darstellung über Accept , die Der Server sollte ehren.

5. Dienstprogramme zum Testen

Wir werden Jackson 2 verwenden, um den unformatierten JSON-String in eine typsichere Java-Entität zu entfernen:

public class GitHubUser { private String login; // standard getters and setters }

Wir verwenden nur ein einfaches Dienstprogramm, um die Tests sauber, lesbar und auf einem hohen Abstraktionsniveau zu halten:

public static  T retrieveResourceFromResponse(HttpResponse response, Class clazz) throws IOException { String jsonFromResponse = EntityUtils.toString(response.getEntity()); ObjectMapper mapper = new ObjectMapper() .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); return mapper.readValue(jsonFromResponse, clazz); }

Beachten Sie, dass Jackson unbekannte Eigenschaften ignoriert, die uns die GitHub-API sendet - das liegt einfach daran, dass die Darstellung einer Benutzerressource auf GitHub ziemlich komplex wird - und wir brauchen hier keine dieser Informationen.

6. Abhängigkeiten

Die Dienstprogramme und Tests verwenden die folgenden Bibliotheken, die alle in Maven Central verfügbar sind:

  • HttpClient
  • Jackson 2
  • Hamcrest (optional)

7. Fazit

Dies ist nur ein Teil dessen, was die gesamte Integrationstestsuite sein sollte. Die Tests konzentrieren sich auf die Sicherstellung der grundlegenden Korrektheit der REST-API , ohne auf komplexere Szenarien einzugehen.

Beispielsweise wird Folgendes nicht behandelt: Erkennbarkeit der API, Verbrauch unterschiedlicher Darstellungen für dieselbe Ressource usw.

Die Implementierung all dieser Beispiele und Codefragmente finden Sie auf Github - dies ist ein Maven-basiertes Projekt, daher sollte es einfach zu importieren und auszuführen sein, wie es ist.