Je vous conseille de réaliser des tests tout au long de la procédure à l’aide de votre debugger, ou en ajoutant de petites méthodes tests à votre application web pour vérifier les fonctionnalités.
Préparez les tests de votre application
Lorsque vous procédez aux tests, vous risquez de rencontrer deux types de bugs. L’un est évident, l’autre est plutôt insidieux.
Évident : Vous construisez et exécutez votre code, mais il ne se compile pas car vous utilisez la mauvaise syntaxe, ou une méthode est manquante quelque part.
Insidieux : Votre code se compile et s'exécute, mais plus tard, alors que vous vous connectez, vous atterrissez sur la mauvaise page d’accueil.
Afin d’éviter la plupart de ces bugs, vous pouvez créer des méthodes tests pour toutes vos méthodes au cours du développement, pour vous assurer que tout fonctionne correctement.
Ce qui est génial avec l’application Spring Boot, c’est qu’elle comprend déjà les librairies de tests dont vous avez besoin pour une application utilisant Spring Boot et Spring Security. Jetons un œil à notre fichier pom.xml.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Nous avons là les dépendances OAuth 2.0, Spring Web et Spring Security.
Mais avez-vous remarqué les dépendances :
spring-boot-starter-test
et spring-security-test
?
Testez votre contrôleur REST avec JUnit 5
Il n’y a pas si longtemps, je m’arrachais les cheveux parce que je ne pouvais pas faire apparaître la page d’accueil après la connexion de l’utilisateur. Pour éviter ça, vous pouvez avoir recours à une simple classe test pour voir si votre contrôleur REST fonctionne, en faisant appel à JUnit.
Rendez-vous sur votre Project Explorer, et cherchez votre dossier src/test/java. Il a été créé pour contenir toutes vos classes tests.
Spring Boot a automatiquement généré une classe de test. Étant donné que ma classe principale s’intitule SpringSecurityAuth, ma classe de test s’appelle SpringSecurityAuthApplicationTests.
Le fichier généré devrait ressembler à ceci :
package com.openclassrooms;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringSecurityAuthApplicationTests {
@Test
void contextLoads() {
}
}
L’import org.junit.jupiter.api.Test
correspond à une librairie de test dans JUnit 5, et vous autorisera à avoir recours à la notation @Test
pour qualifier votre méthode de test.
import org.springframework.boot.test.context.SpringBootTest
est une librairie de test pour les applications Spring Boot MVC.
Cet import est nécessaire à l'annotation @SpringBootTest
.
À quoi sert cette annotation @SpringBootTest
?
Chaque fois que vous ouvrez votre application web Spring Boot, une implémentation de WebApplicationContext, qui étend votre ApplicationContext, est instanciée. L’ApplicationContext est essentiel au démarrage de votre application. Entre autres, il gère les “beans”, c'est-à-dire les objets que Spring va mobiliser pour faire fonctionner votre application. @SpringBootTest
permet à l’objet WebApplicationContext d’être chargé lors de l’exécution de ce test.
Testons le contrôleur que vous avez créé, en réalisant un petit ajout au fichier SpringSecurityAuthApplicationTests.java.
Premièrement, ajoutons les imports suivants :
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.openclassrooms.controller.LoginController;
Remarquez que j’ai ajouté un import pour le contrôleur avec le nom du package (com.openclassrooms.controller
), et le nom de la classe ( LoginController
). Ceci est important, car vous testez le contrôleur REST de la classe LoginController.java.
Il vous faut obtenir une instance du LoginController. Vous le pourrez avec l’annotation @Autowired
.
@SpringBootTest
public class SpringSecurityAuthApplicationTests {
@Autowired
private LoginController controller;
@Test
public void contextLoads(){
}
}
Ensuite, utilisez la méthode assertThat()
et passez l’instance du LoginController en paramètre puis appelez la méthode isNotNull()
.
Cela signifie que l’instance de votre contrôleur ne doit pas être nulle lorsque l’application se lance.
package com.openclassrooms;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.openclassrooms.controller.LoginController;
@SpringBootTest
class SpringSecurityAuthApplicationTests {
@Autowired
private LoginController controller;
@Test
void contextLoads()throws Exception {
assertThat(controller).isNotNull();
}
}
Vous pouvez lancer ce test sur JUnit 5 en faisant un clic droit sur project -> Run as -> JUnit Test.
Lorsque vous exécutez ce code, votre résultat JUnit devrait s’afficher dans un onglet, à côté de votre onglet de console. Un test réussi ne devrait pas déclarer d’erreur, ni d’échec.
Nous avons juste testé si le contrôleur est instancié. Créons maintenant des tests pour vérifier que l’authentification sur notre page login fonctionne !
Testez l’authentification en utilisant MockMvc
Prenons l’exemple d’un test qui utilise vos identifiants de connexion. Vous pouvez avoir recours à ce type de test avec le formLogin()
par défaut, si des utilisateurs sont connectés à la base de données. Vous pouvez créer un faux compte destiné aux tests, en pensant à le supprimer lorsque vous aurez terminé, pour des raisons de sécurité.
À présent, allez dans votre dossier src/java/test où vos autres classes de test sont. Un package devrait déjà être présent pour vos classes de tests. Faites un clic droit sur ce package, puis cliquez sur New -> Class. Vous pouvez l'intituler LoginControllerTest.
Nous allons utiliser un objet MockMVC. Ce dernier crée une fausse version de votre application web, et lance les méthodes qu’il comprend, afin que la fonctionnalité de votre application ne soit pas interrompue. Il utilise les éléments de SpringBootTest et JUnit 5, mais vous permet de créer une instance de l’intégralité de votre configuration d’application web dédiée au test.
Commencez par ajouter les annotations @SpringBootTest
et @AutoConfigureMockMvc
au niveau de la classe.
Comme le montre le code ci-dessous, ajoutez également 1 variable de classe annotée @Autowired
et de type MockMvc
.
@SpringBootTest
@AutoConfigureMockMvc
public class LoginControllerTest{
@Autowired
private MockMvc mvc;
}
Ajoutons quelques tests en créant quatre méthodes :
Tester l’URL /login et vérifier qu’on obtient un statut 200
Tester l’authentification de l’utilisateur avec un login correct.
Tester la non-authentification de l’utilisateur, qui saisit un mot de passe incorrect.
Tester l’URL /user en bypassant la sécurité.
Ces tests ont recours aux méthodes perform()
, andDo()
et andExpect()
.
La méthode perform()
crée une requête GET
en dehors de la méthode de test. La classe ResultActions contient le andDo()
pour exécuter une action générale, et le andExpect()
, pour vérifier un certain résultat.
La classe SecurityMockMvcResultMatchers vérifie les méthodes de ResultActions avec les méthodes authenticated()
et unauthenticated()
.
L’annotation @WithMockUser
mérite d’être notée. Elle permet de bypasser l’étape d’authentification car un utilisateur va automatiquement être authentifié dans le contexte de la méthode de tests concernées. C’est très pratique pour tester nos endpoints sans être bloqué par l’authentification.
Étape 1 : Testez l’URL /login et vérifier qu’on obtient un statut 200.
@Test
public void shouldReturnDefaultMessage() throws Exception {
mvc.perform(get("/login")).andDo(print()).andExpect(status().isOk());
}
Étape 2 : Testez l’authentification en ajoutant les identifiants corrects grâce à la méthode authenticated()
.
@Test
public void userLoginTest() throws Exception {
mvc.perform(formLogin("/login").user("user").password("user")).andExpect(authenticated());
}
Étape 3 : Faites un test pour vous assurer que des identifiants incorrects ne donnent pas lieu à l’authentification de l’utilisateur, avec la méthode unauthenticated()
.
@Test
public void userLoginFailed() throws Exception {
mvc.perform(formLogin("/login").user("user").password("wrongpassword")).andExpect(unauthenticated());
}
Étape 4 : Testez l’URL /user et vérifier qu’on obtient un statut 200. Vous pouvez également vérifier que dans la console le print indique “ Body = Welcome, User”.
@Test
@WithMockUser
public void shouldReturnUserPage() throws Exception {
mvc.perform(get("/user")).andDo(print()).andExpect(status().isOk());
}
Maintenant, vérifiez que vos quatre méthodes fonctionnent :
Tout est au vert, bien joué !
En résumé
Pour vous assurer que vous réalisez vos tests correctement, suivez ces étapes :
Utilisez les méthodes de test fournies par Spring Security et Spring Boot.
Testez votre application et la couche web avec SpringBootTest.
Utilisez MockMvc pour créer une copie de votre application web destinée aux tests.
Testez votre authentification en ayant recours à l'objet MockMvc.
Dans le prochain chapitre, vous apprendrez à personnaliser les exceptions par défaut comme un pro.