BT

Diffuser les Connaissances et l'Innovation dans le Développement Logiciel d'Entreprise

Contribuez

Sujets

Sélectionner votre région

Accueil InfoQ Articles Test Des Applications Web Quarkus : Tests De Composants Et D'intégration

Test Des Applications Web Quarkus : Tests De Composants Et D'intégration

Favoris

Points Clés

  • Quarkus est un framework Java natif Kubernetes full-stack conçu pour les machines virtuelles Java (JVM) et la compilation native
  • Au lieu de réinventer la roue, Quarkus utilise des frameworks bien connus soutenus par des normes / spécifications et les rend compilables en binaire à l'aide de Graal VM
  • Nous commençons ici par une vérification complète de la logique d'un exemple d'application, puis nous verrons étape par étape comment réduire la portée du test en utilisant certaines des fonctionnalités de test de Quarkus
  • Bien que le processus de compilation natif doive fonctionner tout le temps, il est également vrai que lorsqu'un exécutable natif est exécuté, quelques problèmes peuvent survenir. Pour cette raison, il est judicieux d'exécuter des tests sur le binaire exécutable natif
  • La rédaction de tests dans Quarkus n'est pas particulièrement difficile. Le framework fournit suffisamment d'outils pour créer des stubs et créer facilement des mocks (via Mockito, PanacheMock), ainsi que rendre vos tests non dépendants de l'environnement en utilisant l'annotation @TestHTTPEndpoint.

Quarkus est un framework Java natif Kubernetes full-stack conçu pour les machines virtuelles Java (JVM) et la compilation native.

Quarkus optimise Java spécifiquement pour les conteneurs et lui permet de devenir une plate-forme efficace pour les environnements serverless, cloud et Kubernetes. Au lieu de réinventer la roue, Quarkus utilise des frameworks bien connus soutenus par des normes / spécifications et les rend compilables en binaire à l'aide de Graal VM.

Dans cet article, nous allons apprendre à écrire des tests de composants / d'intégration pour les applications Quarkus.

Nous n'allons pas voir les tests unitaires pour une raison simple : les tests unitaires sont écrits sans avoir l'environnement d'exécution dans le contexte du test, donc généralement, ils sont juste écrits avec quelques bibliothèques - à mon avis, Junit5 + Mockito + AssertJ est la meilleure combinaison. Ainsi, tout ce que vous avez utilisé pour vos tests unitaires existants est valide dans une application Quarkus.

Mais qu'en est-il des tests de composants / d'intégration où l'environnement d'exécution entre en scène ? Apprenons à les écrire dans Quarkus.

L'application

Prenons un petit cas d'utilisation dans lequel nous créons une API REST pour enregistrer des utilisateurs.

Tout utilisateur qui souhaite s'inscrire à notre système doit nous fournir un nom d'utilisateur et un e-mail. Ensuite, un mot de passe automatique est généré et l'utilisateur est stocké dans la base de données.

Si nous parlons de la conception de l'application, elle est composée des classes suivantes :

Nous n'allons pas inspecter en profondeur le code de l'application, mais uniquement les parties nécessaires aux tests.

La ressource pour l'inscription

Tout d'abord, vous pouvez voir le endpoint de l'API REST qui implémente les opérations d'inscription :

@Path("/registration")
public class RegistrationResource {

   @Inject
   PasswordGenerator passwordGenerator;

   @GET
   @Path("/{username}")
   @Produces(MediaType.APPLICATION_JSON)
   public Response findUserByUsername(@PathParam("username") String username) {
       return User.findUserByUsername(username)
                   .map(u -> Response.ok(u).build())
                   .orElseGet(() -> Response.status(Status.NOT_FOUND).build());
   }

   @POST
   @Transactional
   @Consumes(MediaType.APPLICATION_JSON)
   public Response insertUser(User user) {
      
       user.password = passwordGenerator.generate();
       user.persist();

       URI userUri = UriBuilder.fromResource(RegistrationResource.class)
                                         .path("/" + user.id).build();
       return Response
                   .created(userUri)
                   .build();
   }
}

Les choses importantes dans cette classe :

  • Il existe deux endpoints, un pour insérer un utilisateur et un pour obtenir des informations à son sujet
  • Il délègue la génération du mot de passe à une implémentation de la classe PasswordGenerator. Elle est injectée à l'aide de CDI (Context and Dependency Injection).
  • La classe User est une implémentation du pattern Active Record. Plus d'informations à ce sujet plus tard

La classe User

L'entité User utilise la spécification JPA (Java Persistence API) et implémente le pattern Active Record. Pour cette raison, il étend la classe PanacheEntity.

@Entity
public class User extends PanacheEntity {
   @Column public String username;
   @Column public String email;
   @Column public String password;

   public static Optional<User> findUserByUsername(String username) {
       return find("username", username).firstResultOptional();
   }
}

Le générateur de mot de passe

La dernière classe importante est le générateur de mot de passe qui crée un mot de passe aléatoire pour l'utilisateur.

@ApplicationScoped
public class RandomPasswordGenerator implements PasswordGenerator {

   @Override
   public String generate() {
       return UUID.randomUUID().toString();
   }
  
}

Il est important de noter ici que RandomPasswordGenerator est un bean géré par le conteneur CDI grâce à l'annotation ApplicationScoped.

Les tests

Nous allons commencer par une vérification logique complète, puis voir étape par étape comment nous pouvons réduire la portée du test en utilisant certaines des fonctionnalités de test de Quarkus.

Commençons par écrire un test de composant qui vérifie que toute la logique est exécutée correctement. Je sais que certains d'entre vous se demandent peut-être "n'est-ce pas un test de bout en bout ?" Et c'est une bonne question, mais attendez une seconde et vous comprendrez pourquoi j'appelle cela un test de composants.

Test des composants. Tester toute la logique.

Nous voulons écrire des tests pour la classe de l'API REST pour vérifier si chaque endpoint REST donne le bon ResponseCode HTTP ou non, s'il renvoie le JSON attendu ou non, etc.

La première chose que nous devons modifier est le serveur de base de données. Si nous voulons valider que tout le flux fonctionne comme prévu, nous avons besoin d'une base de données pour que les utilisateurs puissent être stockés et les retrouver plus tard. Nous pourrions utiliser la même base de données qu'en production, mais cela ralentirait l'exécution du test car la base de données serait déployée à l'extérieur du test, ce qui signifie que les tests devraient attendre que la base de données soit opérationnelle, puis exécuter toutes les opérations de la base de données sur une instance distante.

Puisque nous voulons une exécution de test rapide et que nous ne voulons pas écrire un test de bout en bout ou un test d'intégration, nous utilisons une base de données intégrée en mémoire comme H2.

Pouvons-nous définir une configuration de source de données concrète uniquement pour l'exécution du test ? La réponse est oui, avec les profils Quarkus.

Quarkus vous permet d'avoir plusieurs valeurs de configuration pour la même propriété en la préfixant avec un profil.

Nous pouvons utiliser trois profils par défaut :

  • dev : activé en mode développement (quarkus:dev)
  • test : activé lors de l'exécution des tests
  • prod : le profil par défaut lorsqu'il n'est pas exécuté en mode développement ou test

Pour définir les valeurs de configuration pour chaque profile, nous devons ouvrir le fichier de configuration situé dans src/main/resources/application.properties et utiliser la syntaxe suivante : .config.key=value.

Un exemple de configuration de deux connexions JDBC, une pour le test et une autre pour la production, est présenté dans l'extrait suivant :

quarkus.datasource.jdbc.url=jdbc:mariadb://localhost:3306/mydb
%test.quarkus.datasource.jdbc.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1

Ouvrons le fichier application.properties et configurons une source de données à utiliser lors de l'exécution du test :

%test.quarkus.datasource.db-kind=h2
%test.quarkus.datasource.username=sa
%test.quarkus.datasource.password=
%test.quarkus.datasource.jdbc.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
%test.quarkus.hibernate-orm.database.generation=update

Dans ce cas, H2 est utilisé comme base de données intégrée en mémoire pendant l'exécution du test.

Quarkus s'appuie sur JUnit 5 comme framework de test et sur REST-Assured pour tester et valider les services REST.

L'annotation la plus importante dans un test Quarkus est l'annotation @QuarkusTest . Cette annotation est utilisée pour démarrer l'application Quarkus sur le port 8081. Même si vous avez plusieurs classes de test (toutes annotées par @QuarkusTest), le processus de démarrage de l'application n'est exécuté qu'une seule fois par défaut pour l'ensemble de la suite de tests.

Écrivons une classe de test pour notre test de composant de la boîte blanche. Nous allons maintenant vérifier qu'un utilisateur est bien enregistré.


import io.quarkus.test.junit.QuarkusTest;

import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;

import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response.Status;


@QuarkusTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class RegistrationResourceTest {

   @Test
   @Order(1)
   public void shouldRegisterAUser() {
       final User user = new User();
       user.username = "Alex";
       user.email = "asotobu@example.com";

       given()
         .body(user)
         .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
         .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON)
         .when()
         .post("/registration")
         .then()
            .statusCode(Status.CREATED.getStatusCode())
            .header("location", "http://localhost:8081/registration/1");
   }
}
  • Le test est annoté avec  @QuarkusTest
  • @TestMethodOrder est une annotation JUnit 5 permettant de définir l'ordre d'exécution de chaque cas de test
  • @Order précise l'ordre dans lequel le test est effectué
  • REST-Assured commence par la méthode statique  given()
  • La méthode body() est utilisée pour définir le corps de la requête
  • L'URL de base est définie automatiquement (http://localhost:8081) et il suffit de définir la méthode HTTP et le chemin d'accès à l'aide de la méthode post("/registration")
  • Il vérifie que le code de statut est 201 et que la valeur de l'en-tête location est la bonne

Nous pouvons faire quelque chose de similaire pour tester qu'un utilisateur peut être récupéré à partir de l'application :

@Test
@Order(2)
public void shouldFindAUserByUsername() {
    given()
      .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON)
      .when()
      .get("/registration/{username}", "Alex")
      .then()
         .statusCode(200)
         .body("username", is("Alex"))
         .body("email", is("asotobu@example.com"))
         .body("password", notNullValue());
  • La méthode HTTP est maintenant un get, nous utilisons donc la méthode get()
  • Après la méthode then() vient les assertions. La méthode body() est utilisée pour valider la réponse du contenu du corps. Le premier paramètre est une expression JSON path pour spécifier le champ JSON que nous voulons vérifier et le second paramètre est la valeur attendue

Dans les deux tests, vous remarquerez peut-être que bien que l'URL de base soit automatiquement définie dans REST-Assured, le chemin d'accès ne l'est pas et nous devons le faire manuellement (c'est-à-dire, post("/registration")). Quarkus utilise @io.quarkus.test.common.http.TestHTTPEndpoint pour injecter la configuration du chemin dans REST-Assured. Réécrivons donc le test afin de ne pas avoir à définir le sous-chemin dans chaque requête.

@QuarkusTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@TestHTTPEndpoint(RegistrationResource.class)
public class RegistrationResourceTest {

   @Test
   @Order(1)
   public void shouldRegisterAUser() {
       final User user = new User();
       user.username = "Alex";
       user.email = "asotobu@example.com";

       given()
         .body(user)
         .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
         .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON)
         .when().post()
         .then()
            .statusCode(Status.CREATED.getStatusCode())
            .header("location", "http://localhost:8081/registration/1");
  • Dans l'annotation TestHTTPEndpoint vous définissez la ressource à tester
  • La méthode post() est vide car le chemin est récupéré automatiquement à partir de la ressource

Maintenant, le test est plus résistant aux changements de valeur du chemin car il est automatiquement configuré avec REST-Assured.

Mais il y a quand même une valeur codée en dur sur l'assertion (.header("location", "http://localhost:8081/registration/1")) donc si le test est exécuté sur un autre port ou si le chemin est modifié, alors le test échouerait à cause du refactoring. Quarkus utilise l'annotation @io.quarkus.test.common.http.TestHTTPResource pour injecter le chemin du endpoint dans le test.

@TestHTTPResource
@TestHTTPEndpoint(RegistrationResource.class)
URL url;

@Test
@Order(1)
public void shouldRegisterAUser() {

    final User user = new User();
    user.username = "Alex";
    user.email = "asotobu@example.com";

    given()
      .body(user)
      .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
      .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON)
      .when().post()
      .then()
         .statusCode(Status.CREATED.getStatusCode())
         .header("location", url + "/1");
  • @TestHTTPResource et @TestHTTPEndpoint(RegistrationResource.class) sont utilisés ensemble pour injecter l'URL de base et le chemin d'accès.

Stubbing et Mocking

Jusqu'à présent, nous avons testé l'ensemble de l'application, mais jetez un coup d'œil à l'une des assertions du shouldFindAUserByUsername, plus précisément celle-ci : body("password", notNullValue(). Remarquez que nous n'affirmons pas la valeur (car elle est générée de manière aléatoire), nous vérifions seulement que le champ est défini. Mais que se passe-t-il si nous voulons vérifier non seulement que le mot de passe généré est défini, mais aussi que la valeur est correcte ? Ou que se passe-t-il si la logique prend une seconde pour générer un mot de passe et que nous voulons éviter de faire cet appel coûteux dans nos tests ? Nous avons alors deux possibilités : soit nous stubbons la logique, soit nous nous mockons la logique. Expliquer la différence entre les deux approches n'entre pas dans le cadre de cet article, mais vous pouvez penser à un stub comme un objet qui contient des données prédéfinies tandis que les mocks sont des objets avec des réponses préenregistrées qui enregistrent les appels qu'ils reçoivent pour une validation future.

Voyons comment utiliser des stubs et des mocks dans un test Quarkus.

Stubbing

Pour créer un stub de RandomPasswordGenerator, nous devons créer une implémentation de l'interface PasswordGenerator dans le répertoire src/test/java. De plus, cette classe doit être annotée avec @io.quarkus.test.Mock.

@Mock
public class StaticPasswordGenerator implements PasswordGenerator {

   @Override
   public String generate() {
       return "my-secret-password";
   }
}

Ensuite, nous mettons à jour le test avec le mot de passe concret défini dans la classe du stub :

@Test
@Order(2)
public void shouldFindAUserByUsername() throws InterruptedException {
    given()
      .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON)
      .when().get("/{username}", "Alex")
      .then()
         .statusCode(200)
         .body("username", is("Alex"))
         .body("email", is("asotobu@example.com"))
         .body("password", is("my-secret-password"));

Remarquez que maintenant, nous connaissons le mot de passe à priori, ce qui nous permet de vérifier la valeur concrète retournée par la classe du stub.

Maintenant, lorsque nous effectuons le test, au lieu d'injecter l'instance RandomPasswordGenerator, le StaticPasswordGenerator est injecté dans la classe de la ressource.

L'inconvénient de cette approche est que la même instance de stub est partagée dans toute l'exécution de la suite de tests, ce qui peut être intéressant dans certains cas mais pas dans d'autres.

Quarkus propose également un support l'utilisation de la célèbre bibliothèque Mockito pour écrire des mocks.

Mocking

Pour utiliser Mockito dans Quarkus, nous devons ajouter la dépendance quarkus-junit5-mockito dans le script de notre outil de construction. Par exemple, dans Maven, vous devez ajouter la section suivante dans le pom.xml :

<dependency>
   <groupId>io.quarkus</groupId>
   <artifactId>quarkus-junit5-mockito</artifactId>
   <scope>test</scope>
</dependency>

Pour créer un mock pour notre test, nous devons utiliser l'annotation @io.quarkus.test.junit.mockito.InjectMock pour injecter automatiquement le mock dans le conteneur CDI.

@InjectMock
PasswordGenerator passwordGenerator;

@Test
@Order(1)
public void shouldRegisterAUser() {
      
    Mockito.when(passwordGenerator.generate()).thenReturn("my-secret-password");

    final User user = new User();
    user.username = "Alex";
    user.email = "asotobu@example.com";

    given()
      .body(user)
      .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
      .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON)
      .when().post()
      .then()
         .statusCode(Status.CREATED.getStatusCode())
         .header("location", url + "/1");
  • @InjectMock injecte un mock dans le test. Si vous connaissez le framework Mockito, c'est une sorte d'annotation org.mockito.Mock
  • Le mock ne prend effet que pendant la durée du test de la méthode. Si vous l'utilisez dans la méthode @BeforeAll alors elle est enregistrée pour toute la classe de test
  • Le mock créé est automatiquement injecté dans le conteneur CDI et c'est l'instance injectée dans l'instance de type RegistrationResource

Quarkus offre une expérience agréable lorsqu'il s'agit d'écrire un test en boîte noire, mais qu'en est-il des tests en boîte blanche, lorsque nous nous soucions de la conception interne des classes ou par exemple lorsque nous ne voulons pas tester l'application en faisant un appel REST mais un appel de méthode ? Quarkus nous aide également dans ce domaine.

Test des composants. Test en boîte blanche

Jusqu'à présent, nous avons écrit des tests qui vérifient l'exactitude de l'application en faisant des appels à l'API REST, mais comme nous le savons déjà, parfois nous ne voulons pas tester l'application de l'extérieur (boîte noire) mais de l'intérieur (boîte blanche). Par exemple, dans cette catégorie se trouvent certains types de tests tels que les tests de persistance, les tests d'intégration ou certains tests de composants.

La bonne nouvelle est que tout test dans Quarkus est un bean CDI et cela signifie que tout ce qui est valable dans CDI est également valable dans le test, vous pouvez utiliser @Inject pour injecter tout bean métier, vous pouvez les rendre @Transactional, ou même créer des méta-annotations.

Testons la classe RandomPasswordGenerator mais au lieu de l'instancier directement dans le test, nous allons utiliser l'instance qui est créée par le conteneur CDI, donc elle est proche de ce qui est utilisé en production.


@QuarkusTest
public class PasswordGeneratorTest {
  
   @Inject
   PasswordGenerator passwordGenerator;

   @Test
   public void shouldGenerateARandomPassword() {
       final String password = passwordGenerator.generate();
       assertThat(password).containsPattern("[0-9A-F-]+");
   }
}
  • Comme le test est un bean CDI, une instance de RandomPasswordGenerator est injectée
  • Aucun appel à l'API REST ne se produit, car nous utilisons AssertJ comme bibliothèque d'assertions

Les tests de persistance

Les tests de persistance sont un autre type de test qu'il est utile d'écrire, surtout lorsqu'il n'y a pas de requêtes standard. Comme tout test Quarkus est un bean CDI, il est très facile d'écrire des tests de persistance car tout test peut être transactionnel et un entity manager est instancié.

Écrivons un test de persistance qui valide simplement que trouver un utilisateur par son nom d'utilisateur fonctionne.

@QuarkusTest
public class UserTest {
  
   @Test
   @Transactional
   public void shouldFindUsersByUsername() {

       final User user = new User();
       user.username = "Alex";
       user.email = "asotobu@example.com";
       user.persist();

       Optional<User> foundUser = User.findUserByUsername("Alex");

       assertThat(foundUser)
           .isNotEmpty()
           .map(u -> u.email)
           .contains("asotobu@example.com");

   }
}
  • Le test est transactionnel pour rendre persistant l'insert
  • Un EntityManager est injecté dans l'entité User automatiquement

CONSEIL : l'annotation @Transactional sur les tests signifie que les modifications que votre test apporte à la base de données sont persistantes, ce qui pourrait avoir un effet secondaire dans un autre test. Si vous souhaitez que les modifications apportées soient annulées à la fin du test, vous pouvez annoter le test avec @io.quarkus.test.TestTransaction.

Mais que se passe-t-il si nous devons tester une logique métier qui contient un code de persistance, et que nous ne voulons pas nous fier à la base de données ? Dans un cas normal, nous pourrions créer un mock, mais avec l'implémentation du pattern Active Record de Panache, les opérations sont définies dans l'entité et certaines d'entre elles sont des méthodes statiques (par exemple, des finders), alors comment pouvons-nous les simuler ?

Mocker les tests de persistance

Supposons que nous ayons développé une classe pour regénérer le mot de passe au cas où l'original serait perdu.

Cette classe doit trouver l'objet User puis mettre à jour le mot de passe en utilisant le générateur de mot de passe aléatoire.

@ApplicationScoped
public class RegeneratePassword {
  
   @Inject
   PasswordGenerator passwordGenerator;

   @Transactional
   public void regenerate(String username) {

       final Optional<User> user = User.findUserByUsername(username);
       user.map( u -> {
           String newPassword = passwordGenerator.generate();
           u.password = newPassword;
           return u;
       });

   }
}

Pour utiliser Mockito et Panache dans Quarkus, nous devons ajouter la dépendance quarkus-panache-mock dans notre script d'outil de construction. Par exemple, dans Maven, vous devez ajouter la section suivante dans pom.xml :

<dependency>
  <groupId>io.quarkus</groupId>
  <artifactId>quarkus-panache-mock</artifactId>
  <scope>test</scope>
</dependency>

Pour mocker la dépendance RegeneratePassword dans notre test, nous devons utiliser l'annotation @io.quarkus.test.junit.mockito.InjectMock sur la dépendance PasswordGenerator comme fait dans la section précédente, et aussi utiliser la classe io.quarkus.panache.mock.PanacheMock pour créer un mock de PanacheEntity. Dans notre cas d'utilisation actuel, nous utilisons un appel à PanacheMock.mock(User.class).

@QuarkusTest
public class RegeneratePasswordTest {
  
   @InjectMock
   PasswordGenerator passwordGenerator;

   @Inject
   RegeneratePassword regeneratePassword;

   @Test
   public void shouldGenerateANewPassword() {
      
       Mockito.when(passwordGenerator.generate()).thenReturn("my-secret").thenReturn("password");
      
       PanacheMock.mock(User.class);
       User user = new User("Alex", "alex@example.com", "my_super_password");
       Mockito.when(User.findUserByUsername("Alex")).thenReturn(Optional.of(user));

       regeneratePassword.regenerate("Alex");

       PanacheMock.verify(User.class, Mockito.times(1)).findUserByUsername("Alex");
       assertThat(user.password).isEqualTo("my-secret");

   }
}
  • PanacheMock est utilisé pour mocker l'entité
  • Les méthodes normales de Mockito sont utilisées comme nous le faisons normalement avec les méthodes statiques
  • Pour vérifier toutes les interactions, la méthode PanacheMock.verify doit être utilisée

Tester l'exécutable natif

L'une des fonctionnalités intéressantes fournies par Quarkus est la possibilité de compiler l'application en un exécutable natif à l'aide de GraalVM.

Bien que ce processus devrait toujours fonctionner, il est également vrai que lorsqu'un exécutable natif est exécuté, quelques problèmes peuvent survenir. C'est pourquoi il est judicieux d'effectuer quelques tests sur le fichier exécutable natif.

Quarkus fournit l'annotation io.quarkus.test.junit.NativeImageTest pour que les tests lancent le fichier exécutable natif au lieu de lancer l'application dans la machine virtuelle Java.

Ces types de tests sont généralement exécutés comme tests d'intégration, donc quand un projet Quarkus est échafaudé, Maven Failsafe Plugin est utilisé par opposition à Maven Surefire Plugin. De cette façon, les tests sont exécutés dans la phase integration-test de Maven au lieu de la phase test et les tests doivent se terminer par IT au lieu de Test.

IMPORTANT : Vous devez avoir GraalVM installé sur votre machine afin de compiler vers un exécutable natif.

Une fois GraalVM et les outils native-image (${GRAALVM_HOME}/bin/gu install native-image) installés, nous devons définir la variable d'environnement GRAALVM_HOME vers le répertoire d'installation de GraalVM.

export GRAALVM_HOME=/Users/asotobu/Applications/graalvm-ce-java11-20.2.0/Contents/Home

Faisons un test de la boîte blanche qui vérifie que le fichier natif fonctionne correctement

@NativeImageTest
public class NativeRegistrationResourceIT {

   @Test
   public void shouldRegisterAUser() {
      
       final User user = new User();
       user.username = "Alex";
       user.email = "asotobu@example.com";

       given()
         .body(user)
         .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
         .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON)
         .when().post()
         .then().statusCode(Status.CREATED.getStatusCode());
   }
}
  • l'annotation NativeImageTest est utilisée à la place de l'annotation QuarkusTest

Enfin, nous pouvons créer un exécutable natif et lancer le test en exécutant la commande suivante :

./mvnw integration-test -Pnative

Conclusions

Faire des tests avec Quarkus n'est pas si difficile, et il vous donne suffisamment d'outils pour créer des stubss et créer facilement des mocks (Mockito, PanacheMock) ainsi que pour rendre vos tests non dépendants de l'environnement en utilisant l'annotation @TestHTTPEndpoint.

Mais il y a beaucoup d'autres choses que Quarkus fournit pour vous aider à tester une application et que nous couvrirons dans la seconde partie cet article.

Code source.

A propose de l'auteur

Alex Soto est directeur de l'expérience des développeurs chez Red Hat. Il est passionné par le monde Java, l'automatisation des logiciels et il croit au modèle du logiciel open source. Alex est le co-auteur des livres Testing Java Microservices et Quarkus cookbook et contribue à plusieurs projets open source. Champion Java depuis 2017, il est également conférencier international et enseignant à l'université Salle URL. Vous pouvez le suivre sur Twitter (@alexsotob) pour rester au courant de ce qui se passe dans le monde de Kubernetes et de Java.

 

Evaluer cet article

Pertinence
Style

Contenu Éducatif

BT