J'ai les cours suivants:
classe ApplicationAndConfiguration
package mypackage.service;
import mypackage.service.util.MyUtility;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class ApplicationAndConfiguration {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(ApplicationAndConfiguration.class, new String[]{});
}
@Bean(initMethod="init")
public MyUtility birtUtil() {
return new MyUtility();
}
}
classe MyRestController
package mypackage.service.controllers;
import mypackage.service.util.MyUtility;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyRestController {
@Autowired
private MyUtility util;
@RequestMapping("/getLibraryName")
public String getMessageFromRest(@RequestParam String name) {
return "name was " + name + "//" + util.getMessage();
}
}
classe MyUtility
package mypackage.service.util;
public class MyUtility {
private String message;
public void init() {
setMessage("MyUtility correctly initialized!");
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
Lorsque je démarre l'application et que je l'exécute comme un bocal indépendant, ou depuis le IDE (Eclipse), pas de problème du tout, tout fonctionne comme prévu.
Cependant, je veux écrire un test unitaire pour tester ma classe MyRestController ... et j'obtiens un NPE car l'utilisation du champ Autowired est null ( dans MyRestController classe).
Voici ma classe de test:
package mypackage.service.controllers;
import static org.hamcrest.Matchers.equalTo;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import mypackage.service.ApplicationAndConfiguration;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
@SpringApplicationConfiguration(classes = ApplicationAndConfiguration.class)
@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class TestController {
private MockMvc mvc;
@Before
public void setup() throws Exception {
mvc = MockMvcBuilders.standaloneSetup(new MyRestController()).build();
}
@Test
public void MyTestController() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/getLibraryName").param("name", "test").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().string(equalTo("name was test//MyUtility correctly initialized!")));
}
}
Il me manque définitivement quelque chose pour que mon champ Autowired soit rempli pendant les tests, et pas seulement pendant l'exécution standard de l'application ...
Un pointeur pourquoi cela ne fonctionne pas?
La configuration autonome de MockMvc est destinée aux tests unitaires. Vous effectuez des tests d'intégration lorsque vous créez un contexte Spring dans test. Ne mélangez pas ces deux types de tests.
Il suffit donc de le changer de cette façon:
@SpringApplicationConfiguration(classes = ApplicationAndConfiguration.class)
@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class TestController {
private MockMvc mvc;
@Autowired
private WebApplicationContext webApplicationContext;
@Before
public void setup() throws Exception {
mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
Depuis SpringBoot 1.4, toutes les classes ont été modifiées et obsolètes https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-1.4.0-M2-Release-Notes . Remplacez le Runner et la configuration par ceux ci-dessous. SpringRunner détectera le framework de test pour vous.
@RunWith(SpringRunner.class)
@SpringBootTest(classes = { FileService.class, AppProperties.class, DownloadConfigEventHandler.class })
@EnableConfigurationProperties
public class ConfigMatrixDownloadAndProcessingIntegrationTests extends ConfigMatrixDownloadAbstractTest {
// @Service FileService
@Autowired
private FileService fileService;
// @Configuration AppProperties
@Autowired
private AppProperties properties;
// @Compoenet DownloadConfigEventHandler
@Autowired
private DownloadConfigEventHandler downloadConfigEventHandler;
..
..
}
Toutes ces instances seront câblées automatiquement comme prévu! Même les événements de printemps avec l'éditeur fonctionnent comme prévu comme dans https://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2 .