spring @webMvcTest未排除和加载标记为@Repository的bean

ajsxfq5m  于 2023-03-28  发布在  Spring
关注(0)|答案(4)|浏览(133)

我有一个@RestController,它在@Autowire字段中只有一个依赖项,该依赖项是@component,该组件的类定义有一些自动连接的字段,这些字段是@service,这些服务有一些@ repository。
在整个流程中,我使用了Kafka、Quartz、Cassandra和DB2。因此,当我为控制器创建单元测试用例时,我不想设置整个应用程序。因此,我决定使用@webMvcTest,并在控制器类的唯一依赖项上使用@MockBean。
但是我的测试抛出了异常,因为它试图创建一个标记为@repository的Dao bean。

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

    @MockBean
    MyControllerDependency dependency;

    @Autowired
    MockMvc mockMvc;

    @Test
    void test_something() throws Exception {
       assert(true);
    }
}

下面是代码的简化版本

@Component
class MyControllerDependency { 
    @AutoiWired
    MyCustomService service;
}

@Service
class MyCustomService{

   @Autowired
   MyCustomDao dao;
}

@Repository
class MyCustomDao{
    @Autowired
    private JdbcTemplate template;
}

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

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.

问题是,当我使用@WebMvcTest slice并且已经模拟了唯一需要的依赖项MyControllerDependency时,为什么spring test context试图加载MyCustomDao,它被注解为@Repository
我可以用SpringbootTestAutoconfigureMockMVC进行集成测试,但是为了编写控制器的Junit测试,我需要使用WebMvcTest slice。

0vvn1miw

0vvn1miw1#

我遇到了一个类似的问题,我想使用@WebMvcTest只测试我的控制器,但是spring上下文试图创建不依赖的spring bean,并且失败了,如下所示。
无法加载ApplicationContext java.lang。IllegalStateException:无法加载应用程序上下文,原因是:未满足的依赖项异常:创建文件中定义的名为“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());
        }
    }
}
qf9go6mv

qf9go6mv2#

您的@SpringBootApplication上是否有任何活动的@ComponentScan("...")注解?
如Sping Boot 参考文档中所述:
另一个混淆的来源是类路径扫描。假设,当你以一种合理的方式组织代码时,你需要扫描一个额外的包。你的应用程序可能类似于以下代码:

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

    // ...

}

这样做有效地覆盖了默认的组件扫描指令,其副作用是扫描这两个包,而不管您选择的切片。例如,@DataJpaTest似乎突然扫描了应用程序的组件和用户配置。同样,将自定义指令移动到单独的类是解决此问题的好方法。
一个解决方案是创建一个单独的@Configuration,并使用@ComponentScan进行注解。当创建@WebMvcTest时,配置(及其组件扫描被忽略)。

@Configuration
@ComponentScan("com.example.another")
public class DbConfig {
}
rsl1atfo

rsl1atfo3#

当你在spring Boot main application class上有显式的@ComponentScan annotation时,通常会发生这种情况。
@ComponentScan注解抑制了@Webmvctest的默认组件扫描机制,它向上扫描包层次结构并应用excludeFilters仅查找控制器及其相关类。

3htmauhk

3htmauhk4#

当你使用@MockBean注解来模拟你的bean时,你应该定义当你调用它的方法时被模拟的bean应该做什么,你通常在Mockito中使用when来做这件事。在你的例子中,可以这样做:

@ActiveProfiles("test")
@WebMvcTest
class MyControllerTest {

    @MockBean
    MyControllerDependency dependency;

    @Autowired
    MockMvc mockMvc;

    @Test
    void test_something() throws Exception {
        when(dependency.sample()).thenReturn("Hello, Mock");
        mockMvc.perform(get("/api/test/restpoint")
                .accept(MediaType.APPLICATION_JSON))
               .andDo(print())
               .andExpect(status().isOk());
    }
}

在此行:

when(dependency.sample()).thenReturn("Hello, Mock");

当你发送一个GET请求到/api/test/restpoint路径时,你应该把你的控制器调用的MyControllerDependency类的任何方法都放在dependency.sample()上,而不是dependency.sample(),并且用thenReturn("Hello, Mock")定义那个方法的模拟输出(当它在单元测试中被你的控制器调用时)。

相关问题