【发布时间】:2018-06-27 20:48:41
【问题描述】:
在 Spring Boot 应用程序中,我有两个 POJO,Foo 和 Bar,以及一个 BarToFooConverter,如下所示:
@Component
public class BarToFooConverter implements Converter<Bar, Foo> {
@Override
public Foo convert(Bar bar) {
return new Foo(bar.getBar());
}
}
我还有一个使用转换器的控制器:
@RestController("test")
public class TestController {
@Autowired
private ConversionService conversionService;
@RequestMapping(method = RequestMethod.PUT)
@ResponseBody
public Foo put(@RequestBody Bar bar) {
return conversionService.convert(bar, Foo.class);
}
}
我想用@WebMvcTest 测试这个控制器,类似于:
@WebMvcTest
@RunWith(SpringRunner.class)
public class TestControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void test() throws Exception {
mockMvc.perform(
put("/test")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"bar\":\"test\"}"))
.andExpect(status().isOk());
}
}
但是当我运行这个时,我发现我的BarToFooConverter 没有注册到ConversionService:
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [com.example.demo.web.Bar] to type [com.example.demo.web.Foo]
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:324)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:206)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:187)
at com.example.demo.web.TestController.put(TestController.java:15)
这似乎是有道理的,因为根据the Javadoc:
使用此注解将禁用完全自动配置,而仅应用与 MVC 测试相关的配置(即 @Controller、@ControllerAdvice、@JsonComponent Filter、WebMvcConfigurer 和 HandlerMethodArgumentResolver bean,但不包括 @Component、@Service 或 @Repository bean)。
但是,reference guide 略有不同,表示@WebMvcTest 确实包含Converters:
@WebMvcTest 自动配置 Spring MVC 基础结构并将扫描的 bean 限制为 @Controller、@ControllerAdvice、@JsonComponent、Converter、GenericConverter、Filter、WebMvcConfigurer 和 HandlerMethodArgumentResolver。使用此注解时不会扫描常规 @Component bean。
这里的参考指南似乎不正确 - 还是我的 Converter 注册不正确?
我还尝试在我的测试中模拟ConversionService:
@WebMvcTest
@RunWith(SpringRunner.class)
public class TestControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private ConversionService conversionService;
@Test
public void test() throws Exception {
when(conversionService.convert(any(Bar.class), eq(Foo.class))).thenReturn(new Foo("test"));
mockMvc.perform(
put("/test")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"bar\":\"test\"}"))
.andExpect(status().isOk());
}
}
但现在 Spring 抱怨我的模拟 ConversionService 覆盖了默认值:
Caused by: java.lang.IllegalStateException: @Bean method WebMvcConfigurationSupport.mvcConversionService called as a bean reference for type [org.springframework.format.support.FormattingConversionService] but overridden by non-compatible bean instance of type [org.springframework.core.convert.ConversionService$$EnhancerByMockitoWithCGLIB$$da4e303a]. Overriding bean of same name declared in: null
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.obtainBeanInstanceFromFactory(ConfigurationClassEnhancer.java:402)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:361)
...
理想情况下,我想使用我原来的方法,在我的测试中使用真正的转换器,而不是模拟ConversionService,但使用@WebMvcTest 来限制启动的组件的范围,所以我也尝试使用@WebMvcTest 注解中的includeFilter:
@WebMvcTest(includeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "com.example.demo.web.Bar*"))
但它仍然失败并显示原始的“未找到能够转换...的转换器”错误消息。
这感觉像是一个非常普遍的要求——我错过了什么?
【问题讨论】:
-
我现在没有时间对此进行更彻底的调查,但只是作为发现这一点的人的提及 - Spring 版本似乎有所不同 - 我升级了 Spring Boot 的版本几周前,发现测试开始失败。我现在不记得为什么了,但认为是真正的
ConversionService现在正在被注入,而以前没有。
标签: java spring-mvc spring-boot spring-mvc-test