"No converter found for return value" 当 运行 Spring 启动 MockMvc 测试
"No converter found for return value" when running Spring Boot MockMvc test
我正在尝试创建 Spring 启动控制器的 MockMvc 测试。我特别不希望启动整个应用程序上下文,因此我将上下文限制在有问题的控制器中。但是,测试失败并返回 500,日志输出如下:
2020-03-03 13:04:06.904 WARN 8207 --- [ main] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: No converter found for return value of type: class main.endpoints.ResponseDto]
Spring 引导上下文似乎不知道如何找到 Jackson。
这是控制器
@RestController
class MyController {
@GetMapping("/endpoint")
fun endpoint(): ResponseDto {
return ResponseDto(data = "Some data")
}
}
data class ResponseDto(val data: String)
测试如下:
@SpringBootTest(
classes = [MyController::class],
webEnvironment = SpringBootTest.WebEnvironment.MOCK
)
@AutoConfigureMockMvc
internal class MyControllerTest(@Autowired private val mockMvc: MockMvc) {
@Test
fun `should work`() {
mockMvc.perform(MockMvcRequestBuilders.get("/endpoint").accept(MediaType.APPLICATION_JSON))
.andExpect(
content().json(
"""
{
"data": "Some data"
}
"""
)
)
}
}
build.gradle
文件包含以下依赖项:
def jacksonVersion = "2.10.2"
testImplementation("com.fasterxml.jackson.core:jackson-core:2.10.2")
testImplementation("com.fasterxml.jackson.core:jackson-databind:2.10.2")
testImplementation("com.fasterxml.jackson.core:jackson-annotations:2.10.2")
关于如何让它工作的任何想法?
我不确定,但我认为您需要指定输出的格式。所以像
@GetMapping(value = ["/endpoint"], produces = [MediaType.APPLICATION_JSON])
以便 spring 知道将其转换为 json 而不是说 XML 或其他内容。
解决办法是用@WebMvcTest
而不是@SpringBootTest
来注释class。这配置了足够的上下文,以便测试可以通过 MockMvc
与控制器进行交互。
不幸的是,启用 @WebMvcTest
有另一个副作用:所有由 @Bean
指定的 beans - 配置中注释的方法也被实例化。当这些方法无法在测试环境中执行时(例如,因为它们访问某些环境变量),这是一个问题。
为了解决这个问题,我在测试中添加了注释 @ActiveProfiles("test")
并在每个这样的注释方法中添加了 @Profile("!test")
。这抑制了对这些方法的调用并且测试有效。
@EnableWebMvc
可能会解决您的问题。
根据 Java 文档:
将此注释添加到 @Configuration
class 将从 WebMvcConfigurationSupport
、
导入 Spring MVC 配置
e.g.:
@Configuration
@EnableWebMvc
@ComponentScan(basePackageClasses = MyConfiguration.class)
public class MyConfiguration {
}
要自定义导入的配置,实现接口 WebMvcConfigurer 并覆盖各个方法,例如:
@Configuration
@EnableWebMvc
@ComponentScan(basePackageClasses = MyConfiguration.class)
public class MyConfiguration implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry formatterRegistry) {
formatterRegistry.addConverter(new MyConverter());
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MyHttpMessageConverter());
}
}
我正在尝试创建 Spring 启动控制器的 MockMvc 测试。我特别不希望启动整个应用程序上下文,因此我将上下文限制在有问题的控制器中。但是,测试失败并返回 500,日志输出如下:
2020-03-03 13:04:06.904 WARN 8207 --- [ main] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: No converter found for return value of type: class main.endpoints.ResponseDto]
Spring 引导上下文似乎不知道如何找到 Jackson。
这是控制器
@RestController
class MyController {
@GetMapping("/endpoint")
fun endpoint(): ResponseDto {
return ResponseDto(data = "Some data")
}
}
data class ResponseDto(val data: String)
测试如下:
@SpringBootTest(
classes = [MyController::class],
webEnvironment = SpringBootTest.WebEnvironment.MOCK
)
@AutoConfigureMockMvc
internal class MyControllerTest(@Autowired private val mockMvc: MockMvc) {
@Test
fun `should work`() {
mockMvc.perform(MockMvcRequestBuilders.get("/endpoint").accept(MediaType.APPLICATION_JSON))
.andExpect(
content().json(
"""
{
"data": "Some data"
}
"""
)
)
}
}
build.gradle
文件包含以下依赖项:
def jacksonVersion = "2.10.2"
testImplementation("com.fasterxml.jackson.core:jackson-core:2.10.2")
testImplementation("com.fasterxml.jackson.core:jackson-databind:2.10.2")
testImplementation("com.fasterxml.jackson.core:jackson-annotations:2.10.2")
关于如何让它工作的任何想法?
我不确定,但我认为您需要指定输出的格式。所以像
@GetMapping(value = ["/endpoint"], produces = [MediaType.APPLICATION_JSON])
以便 spring 知道将其转换为 json 而不是说 XML 或其他内容。
解决办法是用@WebMvcTest
而不是@SpringBootTest
来注释class。这配置了足够的上下文,以便测试可以通过 MockMvc
与控制器进行交互。
不幸的是,启用 @WebMvcTest
有另一个副作用:所有由 @Bean
指定的 beans - 配置中注释的方法也被实例化。当这些方法无法在测试环境中执行时(例如,因为它们访问某些环境变量),这是一个问题。
为了解决这个问题,我在测试中添加了注释 @ActiveProfiles("test")
并在每个这样的注释方法中添加了 @Profile("!test")
。这抑制了对这些方法的调用并且测试有效。
@EnableWebMvc
可能会解决您的问题。
根据 Java 文档:
将此注释添加到 @Configuration
class 将从 WebMvcConfigurationSupport
、
e.g.:
@Configuration
@EnableWebMvc
@ComponentScan(basePackageClasses = MyConfiguration.class)
public class MyConfiguration {
}
要自定义导入的配置,实现接口 WebMvcConfigurer 并覆盖各个方法,例如:
@Configuration
@EnableWebMvc
@ComponentScan(basePackageClasses = MyConfiguration.class)
public class MyConfiguration implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry formatterRegistry) {
formatterRegistry.addConverter(new MyConverter());
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MyHttpMessageConverter());
}
}