为什么用WebFlux进行的Spring Boot测试忽略了定制的Jackson模块 [英] Why does spring boot test with webflux ignore custom jackson module

查看:26
本文介绍了为什么用WebFlux进行的Spring Boot测试忽略了定制的Jackson模块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个使用Spring Boot 2.0.1和WebFlux路由器函数的应用程序(不是基于注释!)。对于我的一些数据对象,我编写了扩展StdSerializer的定制序列化程序。我在SimpleModule中注册这些组件,并将该模块公开为一个Bean。

当我运行应用程序时,此设置非常出色。Bean被实例化,REST响应使用正确的序列化程序序列化。

现在我想编写一个测试,以验证路由器功能及其背后的处理程序是否按预期工作。我想嘲笑的是处理程序背后的服务。但是,在测试中,REST响应使用默认序列化程序

我已经创建了一个复制该问题的小型演示项目。完整代码可在此处找到:http://s000.tinyupload.com/?file_id=82815835861287011625

Gradle配置加载Spring Boot和一些依赖项以支持WebFlux和测试。

import io.spring.gradle.dependencymanagement.DependencyManagementPlugin
import org.springframework.boot.gradle.plugin.SpringBootPlugin

buildscript {
    ext {
        springBootVersion = '2.0.1.RELEASE'
    }
    repositories {
        mavenCentral()
        // To allow to pull in milestone releases from Spring
        maven { url 'https://repo.spring.io/milestone' }
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath("io.spring.gradle:dependency-management-plugin:1.0.5.RELEASE")

    }
}

apply plugin: 'java'
apply plugin: SpringBootPlugin
apply plugin: DependencyManagementPlugin


repositories {
    mavenCentral()

    // To allow to pull in milestone releases from Spring
    maven { url 'https://repo.spring.io/milestone' }
}

dependencyManagement {
    imports {
        mavenBom 'org.springframework.boot:spring-boot-dependencies:2.0.1.RELEASE'
    }
}

dependencies {
    compile 'org.springframework.boot:spring-boot-starter-webflux'

    compile 'org.slf4s:slf4s-api_2.12:1.7.25'

    testCompile 'org.springframework.boot:spring-boot-starter-test'
    testCompile 'org.springframework.boot:spring-boot-starter-json'
    testCompile 'junit:junit:4.12'
    testCompile "org.mockito:mockito-core:2.+"
}

该数据对象有两个字段。

package com.example.model;

public class ReverserResult {
    private String originalString;
    private String reversedString;

    // ... constructor, getters
}
自定义序列化程序以与默认序列化程序完全不同的方式呈现数据对象。原始字段名称消失,数据对象的内容被压缩为单个字符串。

@Component
public class ReverserResultSerializer extends StdSerializer<ReverserResult> {
    // ... Constructor ...

    @Override
    public void serialize(ReverserResult value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeStartObject();
        gen.writeFieldName("result");
        gen.writeString(value.getOriginalString() + "|" + value.getReversedString());
        gen.writeEndObject();
    }
}

序列化程序包装在Jackson模块中并公开为Bean。在运行实际应用时,此Bean被正确拾取并添加到ObjectMapper

@Configuration
public class SerializerConfig {
    @Bean
    @Autowired public Module specificSerializers(ReverserResultSerializer reverserResultSerializer) {
        SimpleModule serializerModule = new SimpleModule();
        serializerModule.addSerializer(ReverserResult.class, reverserResultSerializer);

        return serializerModule;
    }
}

我还验证了该Bean实际上存在于测试中。因此,我可以排除在加载Bean时缺少在测试期间创建的上下文。

@RunWith(SpringRunner.class)
@SpringBootTest
public class ReverserRouteTest {
    @Autowired
    public ReverserRoutes reverserRoutes;

    @MockBean
    public ReverserService mockReverserService;

    @Autowired
    @Qualifier("specificSerializers")
    public Module jacksonModule;

    @Test
    public void testSerializerBeanIsPresent() {
        assertNotNull(jacksonModule);
    }

    @Test
    public void testRouteAcceptsCall() {
        given(mockReverserService.reverse(anyString())).willReturn(new ReverserResult("foo", "bar"));

        WebTestClient client = WebTestClient.bindToRouterFunction(reverserRoutes.createRouterFunction()).build();
        client.get().uri("/reverse/FooBar").exchange().expectStatus().isOk();
    }

    @Test
    public void testRouteReturnsMockedResult() {
        given(mockReverserService.reverse(anyString())).willReturn(new ReverserResult("foo", "bar"));

        WebTestClient client = WebTestClient.bindToRouterFunction(reverserRoutes.createRouterFunction()).build();
        client.get().uri("/reverse/somethingcompletelydifferent")
                .exchange()
                .expectBody().json("{"result":"foo|bar"}");
    }
}

运行应用时的结果:

GET http://localhost:9090/reverse/FooBar

HTTP/1.1 200 OK
transfer-encoding: chunked
Content-Type: application/json;charset=UTF-8

{
  "result": "FooBar|raBooF"
}

运行测试时的结果:

< 200 OK
< Content-Type: [application/json;charset=UTF-8]

{"originalString":"foo","reversedString":"bar"}

我还尝试创建我自己的ObjectMapper实例,但也没有使用。我想知道我是不是错过了一个设置(尽管我确实尝试了很多注释...)或者我是不是撞上了虫子。我在谷歌上搜索了很多,但到目前为止,我找到的解决方案都没有帮助。此外,到目前为止,使用路由器功能的人很少:)。

如有任何帮助,我们将不胜感激!

更新:我也尝试过2.0.2.RELEASE和2.1.0.BUILD-20180509。结果总是相同的。

推荐答案

而不是在测试中手动创建WebTestClient,您可以利用@AutoConfigureWebTestClient并按如下方式自动连接它,以便正确考虑您的杰克逊模块:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureWebTestClient
public class ReverserRouteTest {    
    @MockBean
    public ReverserService mockReverserService;

    @Autowired
    @Qualifier("specificSerializers")
    public Module jacksonModule;

    @Autowired
    public WebTestClient client;

    @Test
    public void testSerializerBeanIsPresent() {
        assertNotNull(jacksonModule);
    }

    @Test
    public void testRouteAcceptsCall() {
        given(mockReverserService.reverse(anyString())).willReturn(new ReverserResult("foo", "bar"));

        client.get().uri("/reverse/FooBar").exchange().expectStatus().isOk();
    }

    @Test
    public void testRouteReturnsMockedResult() {
        given(mockReverserService.reverse(anyString())).willReturn(new ReverserResult("foo", "bar"));

        client.get().uri("/reverse/somethingcompletelydifferent")
                .exchange()
                .expectBody().json("{"result":"foo|bar"}");
    }
}

这篇关于为什么用WebFlux进行的Spring Boot测试忽略了定制的Jackson模块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆