web-dev-qa-db-fra.com

Test d'unité de démarrage à ressort Autowired

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?

22
hublo

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();
    }
9
luboskrnac

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 .

27
Marcello de Sales