Spring MVC test dans un contexte sécurisé

0

La phase de test est une étape obligatoire et importante dans le cycle de développement de logiciels quel que soit la méthodologie utilisée.

Spring fournit pour cette étape un ensemble de modules permettant de faciliter le travail de développeur pour la création de tests avec des interactions simples entre les services de Spring (Injection, Sécurité, Transaction…).
Parmi ces modules on trouve le MockMvc qui permet de tester des services REST.

Tester un service Rest

La façon standard pour tester un service Rest consiste à déployer ce service sous un conteneur permettant de le rendre disponible pour test (serveur dédié, mode embarqué avec plugin maven ,…), puis utiliser le RestTemplate de Spring pour simuler le client.

Ce prérequis rend le test d’un service Rest plus complexe que le test d’un bean Spring standard :

  • Nécessite un tiers supplémentaire (tomcat, plugin maven,…).
  • Temps d’exécution plus lent (démarrage et arrêt du conteneur).
  • L’exécution d’un seul cas de test nécessite le déploiement de toute l’application.

Depuis la version 3.2 Spring introduit le framework de test MVC (MockMvc).

MockMvc est un module de SpringTest permettant de simplifier la création de tests Rest et retirer la dépendance explicite à un conteneur web.
Une démonstration complété est disponible sous github.

Initialisation

Le MockMvc fournit un support JUnit pour tester un code Spring MVC d’une manière simple.

  • Introduit dans spring-test.jar.
  • Requête traitée via DispatcherServlet.
  • Pas besoin d’un WEB container pour tester.

On va commencer par une manipulation simple de ce module :

Afin de simplifier l’écriture de nos classes de test, on peut commencer par importer statiquement trois classes clés :

Maintenant on peut configurer notre test pour que spring puisse démarrer le contexte associé :

Que font ces annotations:

  • @WebAppConfiguration : Demander au test runner d’instancier le WebAppConfiguration comme un bean Spring sous le nom ‘webApplicationContext’.
    La présence de cette annotation garantit qu’un web context sera chargé pour le test en utilisant un chemin d’accès par défaut pour la racine de l’application web, ce chemin peut être modifié via l’attribut ‘value’.
  • @ContextConfiguration : Une annotation de Spring Test, permettant de configurer le contexte web de l’application (DataSource, beans, Security,…) chargée pour le test.
    Possible d’injecter une config xml via l’attribut ‘locations’.
    A partir de la version 3.1 Spring introduit la possibilité d’utiliser des classes de configuration (@Configuration) via l’attribut ‘classes’.

Le bean utilisé pour configurer le WebApplicationContext :

Il ne reste qu’à initialiser le mockMvc, cet objet représente un point d’entrée au serveur MVC et de manipulation de différentes entrées REST de l’application.
Cet objet est instancié a partir du contexte web crée précédemment par annotation (@WebAppConfiguration), du coup on aura besoin de récupérer cette instance par injection Spring:

Pour plus de détail:
La classe MockMvcBuilders utilisée précédemment possède deux méthodes permettant d’instancier le MockMvc:

  • Une méthode permettant de builder une instance de MockMvc liée à un web context passé en paramètre. Le DispatcherServlet utilisera ce contexte pour définir l’ensemble de contrôleurs REST de l’application.
  • Une méthode permettant de builder une instance de MockMvc en mode Standalone et enregistrer un ou plusieurs contrôleurs de l’application dans le web context par programmation. Cela est très utile pour tester une partie de l’application.

Finalement tout est prêt pour implémenter notre test:

Pour plus de détail:

  • La méthode perform permet d’envoyer la requête (RequestBuilder ) au serveur Rest puis de retourner un objet de type ResultActions encapsulant la réponse.
  • L’ objet ResultActions permet d’effectuer des assertions enchaînées via la méthode andExpect(),  effectuer des actions (loguer ,…) via la méthode andDo() et finalement retourner la réponse via la méthode andReturn()  qui renvoi un objet MVCResult .
  • L’objet MVCResult permet d’accéder directement à la réponse (contenue, statut, exceptions,…) , par contre son contenue est de type String (json, xml,..) en fonction de format de retour de service Rest, donc on peut mapper manuellement cette réponse pour obtenir un objet:
  • La méthode jsonPath permet d’accéder au contenue de la réponse json a l’aide d’une expression JsonPath afin d’effectuer des assertions sur ses attributs, une dépendance maven est indispensable pour utiliser cet api:

    Une méthode xpath est aussi disponible pour faire la même chose mais avec un contenu de la réponse en xml.

Tester une application sécurisée avec Spring Security

On va changer la configuration de l’application afin d’intégrer Spring Security.
Dans notre exemple, chaque utilisateur de l’application est identifié par un token communiqué via le cookie au serveur.
Un petit aperçu sur la configuration de sécurité de l’application (La config Spring Security n’est pas couvert par cet article).

Le filtre d’authentification:

Maintenant on revient a la configuration de notre test afin d’introduire cette nouvelle fonctionnalité.
Pour que le contexte (WebApplicationContext) de notre test le découvre on devrait intégrer la configuration de sécurité dans le contexte de test :

Jusque là, le MockMvcBuilder n’est pas encore configuré pour appliquer la config de Spring Security.
Pour cela une petite modification à introduire au moment de la création de MockMvc:

Pour plus de détail:

  • La méthode apply() permet d’appliquer une configuration (MockMvcConfigurer) spécifique pour notre environnement de test (exemple la sécurité).
  • La méthode springSecurity() permet de configurer le MockMvcBuilder pour une utilisation avec Spring Security, elle crée un bean Spring sous le nom « springSecurityFilterChain » comme un filtre, et rajoute aussi un TestSecurityContextHolderPostProcessor afin de supporter l’annotation sur la méthode test @WithMockUser>qui permet de créer un utilisateur de test.

Lancer le test avec un utilisateur authentifié par username et password et par annotation:

Il est possible aussi de créer l’utilisateur authentifié par programmation :

Dans notre cas, l’utilisateur de l’application est authentifié par le biais d’un token, donc le builder de la requête permet aussi de créer des cookies :

Le MockHttpServletRequestBuilder fournit encore d’autres moyens pour créer et authentifier un utilisateur de test :

  • authentication(authentication): Utiliser une authentification customisée.
  • securityContext(securityContext): Utiliser un contexte de sécurité customisé.
  • httpBasic(« user »,« password »): Utiliser une authentification http basique.
  • ….

Conclusion

Pour conclure, le framework de Spring Test MVC est un outil complet pour la mise en place de tests unitaires et tests d’intégration pour des services Rest, et c’est un bon moyen pour que le test soit indépendant de son implémentation (déjà il n’y a aucune dépendance de code source de l’application).
Du coup on peut tester nos services Spring MVC sans intégrer le framework Spring MVC lui même.

Partagez cet article.

A propos de l'auteur

Ajouter un commentaire