@webMvcTest 不排除并加载标记为 @Repository 的 bean

Thr*_*ion 13 spring spring-test spring-boot-test

我有一个@RestController 在字段中只有一个依赖项@Autowire ,依赖项是@component,该组件类定义有一些自动装配的字段,它们是@service,这些服务有一些@repositories。

在整个流程中,我使用了 kafka、Quartz、Cassandra 和 DB2,因此当我为控制器创建单元测试用例时,我不想设置整个应用程序。所以我决定使用 @webMvcTest 并在我唯一的一个控制器类依赖项上使用 @MockBean。

但我的测试抛出异常,因为它试图创建一个 Dao bean,它被标记为 @repository。

@ActiveProfiles("test")
@WebMvcTest(controllers = MyControllerTest .class)
class MyControllerTest {

    @MockBean
    MyControllerDependency dependency;

    @Autowired
    MockMvc mockMvc;

    @Test
    void test_something() throws Exception {
       assert(true);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是代码的过于简化的版本

@Component
class MyControllerDependency { 
    @AutoiWired
    MyCustomService service;
}

@Service
class MyCustomService{

   @Autowired
   MyCustomDao dao;
}

@Repository
class MyCustomDao{
    @Autowired
    private JdbcTemplate template;
}
Run Code Online (Sandbox Code Playgroud)

我在测试中遇到以下异常。

Exception

***************************
APPLICATION FAILED TO START
***************************

Description:

Field template in com.....MyCustomDao`  required a bean of type 'org.springframework.jdbc.core.JdbcTemplate' that could not be found.
Run Code Online (Sandbox Code Playgroud)

问题是,当我使用@WebMvcTestslice 并已经模拟了唯一需要的依赖项MyControllerDependency 时,为什么 spring 测试上下文试图加载MyCustomDao注释为 @Repository.

我可以使用SpringbootTest&进行集成测试AutoconfigureMockMVC,但是为了仅为控制器编写 Junit 测试,我需要使用WebMvcTestslice。这造成了一个问题。

小智 26

我遇到了类似的问题,我只想使用 @WebMvcTest 测试我的控制器,但 spring 上下文试图创建非依赖的 spring bean 并且失败,如下所示。

无法加载ApplicationContext java.lang.IllegalStateException:无法加载ApplicationContext 原因:org.springframework.beans.factory.UnsatisfiedDependencyException:创建文件中定义的名为“TestController”的bean时出错...

解决方案:仅加载您测试的控制器,例如@ContextConfiguration(classes = DemoController.class). 另外,请在下面找到完整的示例


    @WebMvcTest
    @ContextConfiguration(classes = DemoController.class)  
    public class DemoControllerTest {    
        @Autowired
        MockMvc mockMvc;

        @MockBean
        DemoService demoService;

        @Test
        public void testGetAllProductCodes_withOutData() throws Exception {
            when(productCodeService.getAllProductCodes())
                    .thenReturn(new ArrayList<ProductCodes>());
            mockMvc.perform(MockMvcRequestBuilders.get("/services/productCodes"))
            .andExpect(MockMvcResultMatchers.status().isNoContent());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么在这个奇怪的世界中 `@ContextConfiguration(classes = DemoController.class)` 有效,而 `@WebMvcTest(controllers = DemoController.class)` 无效,这超出了我的范围。这真的很有帮助。谢谢。 (12认同)
  • @JustvanderVeeken @Eugene 在这里找到了 spring 的源代码和调试。在类/方法“SpringBootTestContextBootstrapper.buildTestContext”中,如果您不使用“ContextConfiguration”,那么在“TestContext”实例中,字段“mergedContextConfiguration.classes”它将指向应用程序的主类而不是控制器,因此它将使用主课程的设置(至少在某种程度上)。 (3认同)

Phi*_*ppS 9

@ComponentScan("...")您的 上有任何激活的注释吗@SpringBootApplication

如Spring Boot 参考文档中所述:

另一个混乱的来源是类路径扫描。假设,当您以合理的方式构建代码时,您需要扫描额外的包。您的应用程序可能类似于以下代码:

@SpringBootApplication
@ComponentScan({ "com.example.app", "com.example.another" })
public class MyApplication {

    // ...

}
Run Code Online (Sandbox Code Playgroud)

这样做可以有效地覆盖默认的组件扫描指令,并具有扫描这两个包的副作用,无论您选择哪个切片。例如,@DataJpaTest 似乎突然扫描应用程序的组件和用户配置。同样,将自定义指令移至单独的类是解决此问题的好方法。

一种解决方案是创建一个单独的并@Configuration@ComponentScan. 创建@WebMvcTest配置时(其组件扫描将被忽略)。

@Configuration
@ComponentScan("com.example.another")
public class DbConfig {
}
Run Code Online (Sandbox Code Playgroud)