Подтвердить что ты не робот

Springboot Unit Test Autowired

У меня есть следующие классы:

Класс 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();
    }
}

Класс 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();
    }   
}

Класс 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;
    }
}

Когда я запускаю приложение и запускаю его как независимую банку или из среды IDE (Eclipse), никаких проблем вообще, все работает так, как ожидалось.

Тем не менее, я хочу написать unit test для проверки моего класса MyRestController... и я получаю NPE, потому что поле Autowired используется null (в классе MyRestController).

Вот мой тестовый класс:

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!")));
    }
}

Мне определенно не хватает чего-то, чтобы поле Autowired заполнялось во время тестов, а не только при стандартном выполнении приложения...

Любой указатель, почему он не работает?

4b9b3361

Ответ 1

Отдельная настройка MockMvc предназначена для модульного тестирования. Вы выполняете интеграционное тестирование при создании контекста Spring в тесте. Не смешивайте эти два типа тестирования.

Так что просто измените его так:

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

Ответ 2

С SpringBoot 1.4 все классы изменились и устарели https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-1.4.0-M2-Release-Notes. Замените Runner и Configuration на приведенные ниже. SpringRunner определит тестовую структуру для вас.

@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;    
  ..
  ..
}

Все эти экземпляры будут автоматически активированы, как и ожидалось! Даже Spring События с издателем работают так, как ожидалось, в https://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2.