向“@WebMvcTest”添加一个额外的 bean
Add one additional bean to "@WebMvcTest"
我有一个控制器和一个使用@WebMvcTest 的测试,它 运行 很好。现在我需要添加一些验证逻辑,为此我 @Autowired
一个额外的 bean(一个 @Component
,一个 MapstructMapper)。
正如预期的那样,由于 @WebMvcTest
,现在测试失败了。 (未发现组件)
有没有办法将一个 bean 添加到创建的上下文中?
由于我使用 @MockBeans
模拟服务层:有没有办法将所有模拟调用委托给真实对象?有了这个我可以模拟映射器并委托给真正的映射器?!
在上下文中获取额外 bean 的一种简单方法是通过在测试 classes
中使用嵌套配置 classes
@TestConfiguration
static class AdditionalConfig {
@Bean
public SomeBean getSomeBean() {
return new SomeBean());
}
}
示例:
场景 - 如果你有一些控制器说 ProductController 并且你有相应的 slice-test 用于 class 说 ProductionControllerTest
@RestController
public class ProductController {
@Autowired
private IProductService productService;
@Autowired
private IProductValidator productValidator;
@GetMapping("product")
public Product getProduct(@RequestParam Long id) {
Product product = productService.getProduct(id); // you are using mockBean of productService
productValidator.validateProduct(product); // you need real bean of productValidator
return product;
}
}
相应的幻灯片测试class 带有额外的 bean 配置
@RunWith(SpringRunner.class)
@WebMvcTest
public class ProductControllerSliceTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private IProductService productService;
@Autowired
private ApplicationContext applicationContext;
@TestConfiguration
static class AdditionalConfig {
@Bean
public IProductValidator productValidator() {
return new ProductValidator();
}
}
@Test
public void testProductGetById() throws Exception {
Product testProductWithID1L = new Product(1L, "testProduct");
when(productService.getProduct(anyLong())).thenReturn(testProductWithID1L);
mockMvc.perform(get("/product")
.param("id", "1")).andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("name")
.value("testProduct"))
.andExpect(MockMvcResultMatchers.jsonPath("id")
.value("1"));
}
}
关于您的场景的其他想法: 如果您真的打算对控制器进行单元测试 class 那么理想情况下您应该模拟 class 你正在测试。
理想情况下,单元测试的目的是只测试被测 object/class 的行为。所有相关的 classes 行为或外部调用都应该被模拟。
当您开始在一个测试下一起测试多个 class 时,您将更多地转向组件测试或集成测试
一个非常简单的解决方案是用 @Import
注释您的测试 class 指定要在测试中使用的其他 bean 的 class(es),作为 stated in documentation:
Typically @WebMvcTest is used in combination with @MockBean or @Import
to create any collaborators required by your @Controller beans.
例如
@WebMvcTest(MyController.class)
@Import(SomeOtherBean.class)
public class SourcingOrganisationControllerTests {
// The controller bean is made available via @WebMvcTest
@Autowired
private MyController myController;
// Additional beans (only one in this case) are made available via @Import
@Autowired
private SomeOtherBean someOtherBean;
}
我有一个控制器和一个使用@WebMvcTest 的测试,它 运行 很好。现在我需要添加一些验证逻辑,为此我 @Autowired
一个额外的 bean(一个 @Component
,一个 MapstructMapper)。
正如预期的那样,由于 @WebMvcTest
,现在测试失败了。 (未发现组件)
有没有办法将一个 bean 添加到创建的上下文中?
由于我使用 @MockBeans
模拟服务层:有没有办法将所有模拟调用委托给真实对象?有了这个我可以模拟映射器并委托给真正的映射器?!
在上下文中获取额外 bean 的一种简单方法是通过在测试 classes
中使用嵌套配置 classes@TestConfiguration
static class AdditionalConfig {
@Bean
public SomeBean getSomeBean() {
return new SomeBean());
}
}
示例:
场景 - 如果你有一些控制器说 ProductController 并且你有相应的 slice-test 用于 class 说 ProductionControllerTest
@RestController
public class ProductController {
@Autowired
private IProductService productService;
@Autowired
private IProductValidator productValidator;
@GetMapping("product")
public Product getProduct(@RequestParam Long id) {
Product product = productService.getProduct(id); // you are using mockBean of productService
productValidator.validateProduct(product); // you need real bean of productValidator
return product;
}
}
相应的幻灯片测试class 带有额外的 bean 配置
@RunWith(SpringRunner.class)
@WebMvcTest
public class ProductControllerSliceTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private IProductService productService;
@Autowired
private ApplicationContext applicationContext;
@TestConfiguration
static class AdditionalConfig {
@Bean
public IProductValidator productValidator() {
return new ProductValidator();
}
}
@Test
public void testProductGetById() throws Exception {
Product testProductWithID1L = new Product(1L, "testProduct");
when(productService.getProduct(anyLong())).thenReturn(testProductWithID1L);
mockMvc.perform(get("/product")
.param("id", "1")).andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("name")
.value("testProduct"))
.andExpect(MockMvcResultMatchers.jsonPath("id")
.value("1"));
}
}
关于您的场景的其他想法: 如果您真的打算对控制器进行单元测试 class 那么理想情况下您应该模拟 class 你正在测试。
理想情况下,单元测试的目的是只测试被测 object/class 的行为。所有相关的 classes 行为或外部调用都应该被模拟。
当您开始在一个测试下一起测试多个 class 时,您将更多地转向组件测试或集成测试
一个非常简单的解决方案是用 @Import
注释您的测试 class 指定要在测试中使用的其他 bean 的 class(es),作为 stated in documentation:
Typically @WebMvcTest is used in combination with @MockBean or @Import to create any collaborators required by your @Controller beans.
例如
@WebMvcTest(MyController.class)
@Import(SomeOtherBean.class)
public class SourcingOrganisationControllerTests {
// The controller bean is made available via @WebMvcTest
@Autowired
private MyController myController;
// Additional beans (only one in this case) are made available via @Import
@Autowired
private SomeOtherBean someOtherBean;
}