Spring Boot 单元测试自动装配
Posted
技术标签:
【中文标题】Spring Boot 单元测试自动装配【英文标题】:Spring Boot Unit Test Autowired 【发布时间】:2016-03-29 22:43:14 【问题描述】:我有以下课程:
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;
当我启动应用程序并将其作为独立 jar 或从 IDE (Eclipse) 运行时,完全没有问题,一切都按预期工作。
但是,我想编写一个单元测试来测试我的 MyRestController 类...我得到了一个 NPE,因为 Autowired 字段 util 为空(在 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 字段在测试期间被填充,而不仅仅是在标准应用程序执行期间......
任何指针为什么它不起作用?
【问题讨论】:
请注意,使用构造函数注入而不是字段注入既有助于识别此类问题,又使独立的单元测试更加容易。 【参考方案1】:自 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 Events with the Publisher 也像 https://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2 中的预期工作。
【讨论】:
即使没有 classes 参数,它也对我有用。谢谢@RunWith
仅适用于 JUnit4,对于 JUnit 5 使用 @ExtendWith(SpringExtension.class)
。【参考方案2】:
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();
【讨论】:
以上是关于Spring Boot 单元测试自动装配的主要内容,如果未能解决你的问题,请参考以下文章
在 Spring Boot 应用程序的 JUnit 测试中,自动装配的 JPA 存储库没有合格的 bean
Spring Boot 自动装配配置类进入 Junit 测试