La version 1.4 de Spring Boot est sortie le 28 juillet 2016. Elle contient notamment des évolutions importantes au niveau de l’écriture des tests.
L’objectif de cet article est de voir comment migrer les tests d’un controller Spring MVC en utilisant les nouvelles fonctionnalités apportées par cette version.
Modification du pom.xml
Le starter de test de Spring Boot 1.4 embarque désormais les dépendances vers AssertJ, JSONassert et JsonPath. Il est donc possible de supprimer l’appel explicite vers ces dépendances dans notre pom, il suffit d’importer le starter :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
Configuration du test
Dans Spring Boot 1.3, il est possible d’écrire un test d’intégration d’un controller avec Spring de la manière suivante :
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = DemoApplication.class)
@WebAppConfiguration
public class DemoControllerTest {
// ...
}
Le test ci-dessus va charger la classe de configuration Spring Boot DemoApplication
à l’intérieur d’un contexte d’application de type WebApplicationContext
. Il sera donc possible de tester le controller avec MockMvc.
Depuis Spring Boot 1.4, l’annotation @SpringBootTest
remplace toutes les annotations existantes pour faire des tests d’intégration avec Spring. De plus, le runner JUnit peut être remplacé par SpringRunner
qui a été introduit dans la version 4.3 de Spring. Finalement, il n’est plus nécessaire de fournir explicitement la classe de configuration Spring Boot. En effet, la classe annotée avec @SpringBootApplication
sera automatiquement utilisée. Le test devient donc :
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoControllerTest {
// ...
}
Gestion des mocks
Pour tester un controller en isolation, il faut l’instancier en mockant ses dépendances (avec Mockito par exemple) et le fournir au builder de MockMvc
.
Avec Spring Boot 1.3, il est possible d’écrire ceci :
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = DemoApplication.class)
@WebAppConfiguration
public class DemoControllerTest {
private MockMvc mockMvc;
@Mock
private DemoService demoService;
@InjectMocks
private DemoController demoController;
@Before
public void setUp() {
Mockito.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(demoController).build();
Mockito.when(demoService.call()).thenReturn(42);
}
}
Spring Boot 1.4 permet de mocker les beans Spring avec Mockito grâce à une annotation spécifique. Ainsi, le bean de l’ApplicationContext
est remplacé par un mock et Spring se charge donc de l’injecter dans le controller. Le test devient donc le suivant :
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoControllerTest {
private MockMvc mockMvc;
@MockBean
private DemoService demoService;
@Autowired
private DemoController demoController;
@Before
public void setUp() {
this.mockMvc = MockMvcBuilders.standaloneSetup(demoController).build();
Mockito.when(demoService.call()).thenReturn(42);
}
}
Dans ce test, le contexte d’application est chargé dans son intégralité avec le bean DemoService
remplacé par un mock. Le DemoController
injecté utilisera donc ce mock.
Limitation de la configuration chargée
Dans ce contexte, il n’est pas forcément nécessaire de charger tout le contexte d’application pour tester uniquement le controller.
Spring Boot 1.4 introduit l’annotation @WebMvcTest
qui permet de tester spécifiquement des controllers Spring MVC avec MockMvc
. Ainsi, seule la configuration Spring MVC sera chargée. Le test précédent peut donc s’écrire de la manière suivante :
@RunWith(SpringRunner.class)
@WebMvcTest(DemoController.class)
public class DemoControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private DemoService demoService;
@Before
public void setUp() {
Mockito.when(demoService.call()).thenReturn(42);
}
}
MockMvc
n’a plus besoin d’être instancié explicitement dans le setup. Grâce à l’annotation @WebMvcTest
, l’instance peut être directement injectée dans le test.
Conclusion
Les évolutions apportées par Spring Boot 1.4 au niveau des tests permettent de simplifier l’écriture des tests d’intégration. En effet, il n’y a plus qu’une seule annotation à utiliser (@SpringBootTest
). De plus, l’intégration de Mockito dans Spring Boot permet de remplacer directement des beans du contexte d’application par des mocks. Finalement, dans le cadre du test d’un controller Spring MVC avec MockMvc
, l’annotation @WebMvcTest
permet de ne charger que les beans nécessaires à l’exécution des tests.