@webMvcTest 不排除和加载标记为 @Repository 的 bean
@webMvcTest is not excluding and loading beans marked as @Repository
我有一个 @RestController
,它在字段 @Autowire
中只有一个依赖项
该依赖项是@component,该组件Class定义有一些自动装配的字段,它们是@service,那些服务有一些@repositories。
在整个流程中,我使用了 kafka、Quartz、Cassandra 和 DB2
因此,当我为我的控制器创建单元测试用例时,我不想设置整个应用程序。所以我决定使用 @webMvcTest 并在我唯一的控制器依赖项上使用 @MockBean class.
但是我的测试抛出异常,因为它试图创建一个标记为 @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 测试上下文试图加载 MyCustomDao
注释为 @Repository
.
我可以使用 SpringbootTest
和 AutoconfigureMockMVC
进行集成测试,但是为了只为控制器编写 Junit 测试,我需要使用 WebMvcTest
slice。这造成了一个问题。
当你使用 @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");
而不是 dependency.sample()
你应该把 MyControllerDependency
class 的任何方法放在你的控制器调用时,当你向 /api/test/restpoint
路径发送 GET
请求时thenReturn("Hello, Mock")
您定义该方法的模拟输出是什么(当它在您的单元测试中被您的控制器调用时)。
当您在 spring 引导主应用程序 class.
上有明确的 @ComponentScan 注释时,通常会发生这种情况
@ComponentScan 注释抑制了@Webmvctest 发生的默认组件扫描机制,它向上扫描包层次结构并应用 excludeFilters 以仅查找控制器及其相关 classes。
我 运行 遇到了一个类似的问题,我只想使用 @WebMvcTest 测试我的控制器,但是 spring 上下文试图创建非依赖性 spring beans 并且失败了下面。
无法加载 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());
}
}
}
您的 @SpringBootApplication
上是否有任何 @ComponentScan("...")
注释处于活动状态?
如Spring Boot Reference Documentation所述:
Another source of confusion is classpath scanning. Assume that, while you structured your code in a sensible way, you need to scan an additional package. Your application may resemble the following code:
@SpringBootApplication
@ComponentScan({ "com.example.app", "com.example.another" })
public class MyApplication {
// ...
}
Doing so effectively overrides the default component scan directive with the side effect of scanning those two packages regardless of the slice that you chose. For instance, a @DataJpaTest seems to suddenly scan components and user configurations of your application. Again, moving the custom directive to a separate class is a good way to fix this issue.
一个解决方案是创建一个单独的 @Configuration
,用 @ComponentScan
注释。创建 @WebMvcTest
配置时(及其组件扫描被忽略)。
@Configuration
@ComponentScan("com.example.another")
public class DbConfig {
}
我有一个 @RestController
,它在字段 @Autowire
中只有一个依赖项
该依赖项是@component,该组件Class定义有一些自动装配的字段,它们是@service,那些服务有一些@repositories。
在整个流程中,我使用了 kafka、Quartz、Cassandra 和 DB2 因此,当我为我的控制器创建单元测试用例时,我不想设置整个应用程序。所以我决定使用 @webMvcTest 并在我唯一的控制器依赖项上使用 @MockBean class.
但是我的测试抛出异常,因为它试图创建一个标记为 @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 测试上下文试图加载 MyCustomDao
注释为 @Repository
.
我可以使用 SpringbootTest
和 AutoconfigureMockMVC
进行集成测试,但是为了只为控制器编写 Junit 测试,我需要使用 WebMvcTest
slice。这造成了一个问题。
当你使用 @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");
而不是 dependency.sample()
你应该把 MyControllerDependency
class 的任何方法放在你的控制器调用时,当你向 /api/test/restpoint
路径发送 GET
请求时thenReturn("Hello, Mock")
您定义该方法的模拟输出是什么(当它在您的单元测试中被您的控制器调用时)。
当您在 spring 引导主应用程序 class.
上有明确的 @ComponentScan 注释时,通常会发生这种情况@ComponentScan 注释抑制了@Webmvctest 发生的默认组件扫描机制,它向上扫描包层次结构并应用 excludeFilters 以仅查找控制器及其相关 classes。
我 运行 遇到了一个类似的问题,我只想使用 @WebMvcTest 测试我的控制器,但是 spring 上下文试图创建非依赖性 spring beans 并且失败了下面。
无法加载 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());
}
}
}
您的 @SpringBootApplication
上是否有任何 @ComponentScan("...")
注释处于活动状态?
如Spring Boot Reference Documentation所述:
Another source of confusion is classpath scanning. Assume that, while you structured your code in a sensible way, you need to scan an additional package. Your application may resemble the following code:
@SpringBootApplication
@ComponentScan({ "com.example.app", "com.example.another" })
public class MyApplication {
// ...
}
Doing so effectively overrides the default component scan directive with the side effect of scanning those two packages regardless of the slice that you chose. For instance, a @DataJpaTest seems to suddenly scan components and user configurations of your application. Again, moving the custom directive to a separate class is a good way to fix this issue.
一个解决方案是创建一个单独的 @Configuration
,用 @ComponentScan
注释。创建 @WebMvcTest
配置时(及其组件扫描被忽略)。
@Configuration
@ComponentScan("com.example.another")
public class DbConfig {
}