我的目标是将以前使用
Spring Boot 1.3开发的Spring Boot应用程序迁移到最新的Spring Boot 1.4版本.该应用程序由几个maven模块组成,其中只有一个包含使用@SpringBootApplication注释的类.
迁移的一部分是使用@WebMvcTest注释来有效地测试控制器,在这里我遇到了一个问题.
考虑来自Spring Boot github页面的example application. @WebMvcTest注释工作得很好,因为据我所知(在我做了几次测试之后),主包中有一个用@SpringBootApplication注释的类.请注意,我遵循上面示例中显示的相同概念,用于我自己的@WebMvcTest测试.
我在应用程序中看到的唯一区别是,控制器类位于一个单独的maven模块中(没有@SpringBootApplication注释类),但具有@Configuration和SpringBootConfiguration配置.如果我没有用@SpringBootApplication注释任何类,我总是在测试控制器时得到一个断言.我的断言与上面示例中的SampleTestApplication类修改为仅具有@EnableAutoConfiguration和@SpringBootConfiguration注释(@SpringBootApplication不存在)时的断言相同:
getVehicleWhenRequestingTextShouldReturnMakeAndModel(sample.test.web.UserVehicleControllerTests) Time elapsed: 0.013 sec <<< FAILURE!
java.lang.AssertionError: Status expected:<200> but was:<404>
at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:54)
at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:81)
at org.springframework.test.web.servlet.result.StatusResultMatchers$10.match(StatusResultMatchers.java:664)
at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:171)
at sample.test.web.UserVehicleControllerTests.getVehicleWhenRequestingTextShouldReturnMakeAndModel(UserVehicleControllerTests.java:68)
我应该怎么处理?我是否应始终使用@SpringBootApplication注释类以运行@WebMvcTest测试?
编辑1:我做了一个带有2个模块和最小配置的小型maven项目.它是here.现在,我得到另一个模块中定义的存储库的NoSuchBeanDefinitionException异常.如果我配置“完整”@SpringBootApplication – 一切都很好.
编辑2:我从编辑1修改了小测试项目,给出了一个原始问题.我正在玩不同的注释并在配置类上添加了@ComponentScan,因为我怀疑bean没有正确注册.但是,我希望只有@Controller bean(在@WebMvcTest(… class)中定义)才能根据@WebMvcTest行为背后的魔法进行注册.
编辑3:Spring Boot项目issue.
最佳答案 简短的回答:我相信.
答案很长:
我相信@WebMvcTest需要找到SpringBootApplication配置,因为WebMvcTest的唯一目的是帮助简化测试(SpringBootApplication宁愿尝试加载整个世界).
在您的特定情况下,由于您的非测试包中没有任何内容,我相信它还会找到使用@ScanPackages注释的SampleTestConfiguration,并以某种方式加载每个bean.
在src / main / java / sample / test中添加以下内容
@SpringBootApplication
public class SampleTestConfiguration {
}
并将您的测试更改为:
@RunWith(SpringRunner.class)
@WebMvcTest(MyController.class)
public class MyControllerTest {
@Autowired
private MockMvc mvc;
@MockBean
private MyService ms;
@Autowired
private ApplicationContext context;
@Test
public void getDataAndExpectOkStatus() throws Exception {
given(ms.execute("1")).willReturn(false);
mvc.perform(get("/1/data").accept(MediaType.APPLICATION_JSON_VALUE)).andExpect(status().isOk()).andExpect(content().string("false"));
}
@Test
public void testMyControllerInAppCtx() {
assertThat(context.getBean(MyController.class), is(not(nullValue())));
}
@Test
public void testNoMyAnotherControllerInAppCtx() {
try {
context.getBean(MyAnotherController.class);
fail("Bean exists");
} catch (BeansException e) {
// ok
}
}
}
@WebMvcTest找到SpringBootApplication,然后只加载有限数量的bean(参见documentation):
@WebMvcTest will auto-configure the Spring MVC infrastructure and
limit scanned beans to @Controller, @ControllerAdvice, @JsonComponent,
Filter, WebMvcConfigurer and HandlerMethodArgumentResolver. Regular
@Component beans will not be scanned when using this annotation.
WebMvcTest需要SpringBootApplication:WebMvcTest继承了许多AutoConfiguration,因此需要SpringBoot来加载它们.然后它禁用许多其他AutoConfiguration,您的控制器变得易于测试.
使用WebMvcTest的关键在于你有一个SpringBootApplication并希望通过禁用除控制器之外的所有bean来简化测试.如果您没有SpringBootApplication,那么为什么要使用WebMvcTest呢?