当前位置: 首页 > 知识库问答 >
问题:

@WebMvcTest是否需要@SpringBootApplication注释?

仲孙奇
2023-03-14

我的目标是将以前使用Spring Boot 1.3开发的Spring Boot应用程序迁移到最新的Spring Boot 1.4版本。该应用程序由几个maven模块组成,其中只有一个包含用SpringBootApplication注释的类。

迁移的一部分是使用WebMvcTest注释来有效地测试控制器,这里我遇到了一个问题。

考虑Spring Boot github页面中的一个示例应用程序<代码>@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)

我该怎么处理?为了运行@WebMvcTest测试,我是否应该始终使用@SpringBootApplication注释类?

编辑1:我做了一个小的maven项目,有2个模块和一个最小的配置。它就在这里。现在,我得到了另一个模块中定义的存储库的NoSuchBeanDefinitionException异常。如果我在SpringBootApplication中配置“full”,一切都很好。

编辑2:我从EDIT 1修改了小型测试项目以给出一个原始问题。我正在玩不同的注释并在配置类上添加了@ComponentScan,因为我怀疑bean没有正确注册。但是,我希望只有@Controller bean(在@WebMvcTest(... class)中定义)应该根据@WebMvcTest行为背后的魔法进行注册。

编辑3:Spring Boot项目问题。


共有3个答案

栾峰
2023-03-14

是的,根据spring boot文档

搜索算法从包含测试的包开始工作,直到找到一个@SpringBootApplication或@SpringBootConfiguration注释类。只要您以合理的方式构造代码,通常就会找到您的主配置。

但在我开始使用WebMvcTest之后,spring boot仍然尝试加载其他bean,最后,TypeExcludeFilter成功了。

    @RunWith(SpringRunner.class)
    @WebMvcTest(controllers = {JzYsController.class} )
    public class JzYsControllerTest {

        private static final String REST_V4_JZYS = "/rest/v4/JzYs";

        @Autowired
        private MockMvc mockMvc;

        @MockBean
        private JzYsService service;

        @Test
        public void deleteYsByMlbh() throws Exception {
            Mockito.when(service.deleteYsByMlbh(Mockito.anyString())).thenReturn(Optional.of(1));
            mockMvc.perform(delete(REST_V4_JZYS + "?mbbh=861FA4B0E40F5C7FECAF09C150BF3B01"))
            .andExpect(status().isNoContent());
        }

        @SpringBootConfiguration
        @ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class))
        public static class config{
        }
    }
穆招
2023-03-14

这是一个老生常谈的话题,但这里没有提到一个解决方案

您可以仅在您的测试源代码中创建一个用SpringBootApplication注释的类。然后,您仍然拥有一个很好的项目多模块结构,只有一个“真正的”SpringBootApplication

白泽语
2023-03-14

简短回答:我相信是这样。

详细回答:

我相信WebMvcTest需要找到SpringBootApplication配置,因为WebMvcTest的唯一目的是帮助简化测试(SpringBootApplication宁愿尝试加载整个世界)。

在您的特定情况下,由于您的非测试包中没有任何,我相信它还会找到SampleTestConfiguration,它用@ScanPackages注释并以某种方式加载每个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(请参阅文档):

@WebMvcTest将自动配置Spring MVC基础架构,并将扫描的bean限制为@Controller、@ControllerAdvice、@JsonComponent、Filter、WebMvcConfigurer和HandlerMethodArgumentResolver。使用此注释时,将不会扫描常规@组件bean。

WebMvcTest需要SpringBootApplicationWebMvcTest继承了许多AutoConfiguration,因此需要SpringBoot来加载它们。然后它禁用了许多其他AutoConfiguration,您的控制器变得易于测试。

使用WebMvcTest的全部意义在于当您有SpringBootApplication并且您希望通过禁用除控制器之外的所有bean来简化测试。如果您没有SpringBootApplication,那么为什么要使用WebMvcTest呢?

 类似资料:
  • 我的@SpringBootApplication注释存在于包中。 根据本文,使用@SpringBootApplication注释等同于使用@Configuration、@EnableAutoConfiguration和@ComponentScan及其默认属性:- https://docs.spring.io/spring-boot/docs/2.0.x/reference/html/using-b

  • 随着新的工具栏小部件的引入和AppCompat(android.support.v7.widget.Toolbar)版本的推出,是否还需要调用setSupportActionbar(工具栏)?或者调用setSupportActionbar有什么好处吗;现在我们可以设置标题、子标题、导航图标、导航图标单击侦听器(getSupportActionBar()。直接在工具栏上设置DisplayHomeAs

  • 我希望确认有效的已签名 SAML 注销请求是否需要 RelayState。 我们已经将微软的ADFS 2012 R2与甲骨文的身份联合会联合起来,其中ADFS是SP,OIF是IdP。作为基础,我们遵循将ADFS 2.0/3.0 SP与OIF IdP集成。 一切正常,除了注销。我们有另一个 SP 执行注销并与 OIF 合作。我们发现的一个区别是,ADFS 不会发送带有其签名注销请求的 RelaySt

  • 问题内容: 我正在使用Hibernate Search,文档和书籍说我在id字段上需要@DocumentId,以便Hibernate Search可以知道如何将索引映射到对象。 没有代码中的@DocumentId,我的代码似乎运行良好。Hibernate Search是否变得足够聪明,以至于@Id字段是一个很好的默认值?是否会引起一些不明显的问题? 谢谢你的时间! 问题答案: 如果您使用的是老式的

  • 问题内容: 以下代码: 是/是打开JDBC连接所必需的。 我听说现代JDBC驱动程序不再需要它。但是我无法在项目中将其删除,因为我遇到了异常。我正在使用Java7和tomcat7。 什么时候可以省略构建? 问题答案: 从JDBC 4.0开始,不需要Class.forName()。 这是JDBC的Java教程的摘录。 在 早期 版本的JDBC中,要获得连接,首先必须通过调用方法Class.forNa

  • 问题内容: 我需要从该站点下载哪个tar? 我已经尝试过fortrans,但是一直出现此错误(明显地设置了环境变量之后)。 问题答案: 该SciPy的网页用来提供构建和安装说明,但说明现在依靠操作系统二进制分发。要在没有预编译所需库软件包的操作系统上构建SciPy(和NumPy),必须先构建然后静态链接到Fortran库BLAS和LAPACK: 仅执行五个g77 / gfortran / ifor