运行 Spring Boot MockMvc 测试时“找不到返回值的转换器”

Posted

技术标签:

【中文标题】运行 Spring Boot MockMvc 测试时“找不到返回值的转换器”【英文标题】:"No converter found for return value" when running Spring Boot MockMvc test 【发布时间】:2020-06-15 19:37:33 【问题描述】:

我正在尝试创建一个 Spring Boot 控制器的 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 Boot 上下文似乎不知道如何找到 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")

关于如何让它发挥作用的任何想法?

【问题讨论】:

【参考方案1】:

解决方案是使用@WebMvcTest 而不是@SpringBootTest 来注释类。这配置了足够的上下文,测试可以通过MockMvc 与控制器进行交互。

不幸的是,启用@WebMvcTest 有另一个副作用:配置中@Bean-annotated 方法指定的所有bean 也会被实例化。当这些方法无法在测试环境中执行时(例如,因为它们访问某些环境变量),就会出现问题。

为了解决这个问题,我在测试中添加了注解@ActiveProfiles("test"),在每个这样的注解方法中添加了@Profile("!test")。这会抑制对这些方法的调用,并且测试有效。

【讨论】:

【参考方案2】:

我不确定,但我认为您需要指定输出的格式。所以像

@GetMapping(value = ["/endpoint"], produces = [MediaType.APPLICATION_JSON])

这样spring就知道把它转换成json而不是说xml什么的。

【讨论】:

添加 produces = "application/json" 会将错误更改为以下内容:org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation 端点在生产中工作正常,因此必须更改它以进行测试是没有意义的。 啊,我没有意识到这是一个测试特定的情况。在这种情况下,问题可能与您的测试上下文有关,缺少某些东西。我认为您正在尝试手动执行某些操作,以防止弹簧启动已经支持的完整上下文启动。将测试上方的注释更改为 @WebMvcTest(MyController.class) 和自动装配 MockMvc ,它应该做你想做的事(只是旋转 web 层,只有一个控制器),另见:spring.io/guides/gs/testing-web (WebMvcTest 解释了所有底部的路。【参考方案3】:

@EnableWebMvc 可能会解决您的问题。 根据Java Doc:

将此注解添加到@Configuration 类会从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 Boot MockMvc 测试时“找不到返回值的转换器”的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot RestApi 测试教程 Mock 的使用

Spring Boot MVC 测试 - MockMvc 始终为空

使用 spring-data-jpa 和 MockMvc 进行 spring boot junit 测试

spring boot 测试无法注入 TestRestTemplate 和 MockMvc

Spring Boot 应用程序在 mockmvc 测试中失败

在 Spring Boot with Slice 中使用 MockMVC 测试静态内容