Tester une API REST avec Java

Tester une API REST avec Java

1. Vue d'ensemble

Ce tutoriel se concentre sur les principes de base et la mécanique detesting a REST API with live Integration Tests (avec une charge utile JSON).

# # L'objectif principal est de fournir une introduction au test de l'exactitude de base de l'API - et nous allons utiliser la dernière version desGitHub REST API pour les exemples.

Pour une application interne, ce type de test s'exécute généralement en tant qu'étape tardive d'un processus d'intégration continue, consommant l'API REST après son déploiement.

Lors du test d'une ressource REST, il y a généralement quelques responsabilités orthogonales sur lesquelles les tests doivent se concentrer:

  • les HTTPresponse code

  • autres HTTPheaders dans la réponse

  • lespayload (JSON, XML)

Each test should only focus on a single responsibility and include a single assertion. Se concentrer sur une séparation claire a toujours des avantages, mais lors de ce type de test de boîte noire est encore plus important, car la tendance générale est d'écrire des scénarios de test complexes au tout début.

Un autre aspect important des tests d'intégration est le respect desSingle Level of Abstraction Principle - la logique d'un test doit être écrite à un niveau élevé. Des détails tels que la création de la requête, l'envoi de la requête HTTP au serveur, la gestion des E / S, etc. ne doivent pas être effectués en ligne, mais via des méthodes utilitaires.

Lectures complémentaires:

Test d'intégration au printemps

Guide rapide pour la rédaction de tests d'intégration pour une application Web Spring.

Read more

Test en démarrage de printemps

Découvrez comment Spring Boot prend en charge les tests pour écrire efficacement des tests unitaires.

Read more

Un guide de REST-assuré

Explorez les bases de REST-assuré - une bibliothèque qui simplifie le test et la validation des API REST.

Read more

2. Test du code d'état

@Test
public void givenUserDoesNotExists_whenUserInfoIsRetrieved_then404IsReceived()
  throws ClientProtocolException, IOException {

    // Given
    String name = RandomStringUtils.randomAlphabetic( 8 );
    HttpUriRequest request = new HttpGet( "https://api.github.com/users/" + name );

    // When
    HttpResponse httpResponse = HttpClientBuilder.create().build().execute( request );

    // Then
    assertThat(
      httpResponse.getStatusLine().getStatusCode(),
      equalTo(HttpStatus.SC_NOT_FOUND));
}

C'est un test assez simple -it verifies that a basic happy path is working, sans ajouter trop de complexité à la suite de tests.

Si, pour une raison quelconque, il échoue, il n'est pas nécessaire de rechercher un autre test pour cette URL tant que ce problème n'est pas corrigé.

3. Test du type de support

@Test
public void
givenRequestWithNoAcceptHeader_whenRequestIsExecuted_thenDefaultResponseContentTypeIsJson()
  throws ClientProtocolException, IOException {

   // Given
   String jsonMimeType = "application/json";
   HttpUriRequest request = new HttpGet( "https://api.github.com/users/eugenp" );

   // When
   HttpResponse response = HttpClientBuilder.create().build().execute( request );

   // Then
   String mimeType = ContentType.getOrDefault(response.getEntity()).getMimeType();
   assertEquals( jsonMimeType, mimeType );
}

Cela garantit que la réponse contient réellement des données JSON.

Comme vous l'avez peut-être remarqué,we’re following a logical progression of tests - d'abord le code d'état de la réponse (pour s'assurer que la demande était correcte), puis le type de support de la réponse, et ce n'est que dans le test suivant que nous examinerons la charge utile JSON réelle.

4. Test de la charge utile JSON

@Test
public void
  givenUserExists_whenUserInformationIsRetrieved_thenRetrievedResourceIsCorrect()
  throws ClientProtocolException, IOException {

    // Given
    HttpUriRequest request = new HttpGet( "https://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() ) );
}

Dans ce cas, je sais que la représentation par défaut des ressources GitHub est JSON, mais généralement, l'en-tête `++`Content-Type de la réponse doit être testé à côté de l'en-têteAccept de la demande - le client demande pour un type particulier de représentation viaAccept, que le serveur doit honorer.

5. Utilitaires de test

Nous allons utiliser Jackson 2 pour démarshall la chaîne JSON brute en une entité Java de type sécurisé:

public class GitHubUser {

    private String login;

    // standard getters and setters
}

Nous n'utilisons qu'un simple utilitaire pour garder les tests propres, lisibles et à un niveau d'abstraction élevé:

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);
}

Notez queJackson is ignoring unknown properties que l'API GitHub nous envoie - c'est simplement parce que la représentation d'une ressource utilisateur sur GitHub devient assez complexe - et nous n'avons besoin d'aucune de ces informations ici.

6. Les dépendances

Les utilitaires et les tests utilisent les bibliothèques suivantes, toutes disponibles dans Maven central:

7. Conclusion

Ce n'est qu'une partie de ce que devrait être la suite complète de tests d'intégration. Les tests se concentrent surensuring basic correctness for the REST API, sans entrer dans des scénarios plus complexes,

Par exemple, les éléments suivants ne sont pas couverts: découvrabilité de l'API, consommation de différentes représentations pour la même ressource, etc.

[.iframe-fluid] ##

L'implémentation de tous ces exemples et extraits de code peut être trouvéeover on Github - il s'agit d'un projet basé sur Maven, il devrait donc être facile à importer et à exécuter tel quel.