Я пишу приложение с использованием функций Spring Boot 2.0.1 и маршрутизатора WebFlux ( не на основе аннотаций!). Для некоторых моих объектов данных я написал собственные сериализаторы, которые расширяют StdSerializer
. Я регистрирую их в SimpleModule
и выставляю этот модуль как компонент.
Эта настройка работает как чудо, когда я запускаю приложение. Компонент создается, а ответы 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();
}
}
Сериализатор обернут в модуль Джексона и выставлен как боб. Этот компонент правильно выбран и добавлен в ObjectMapper
при запуске самого приложения.
@Configuration
public class SerializerConfig {
@Bean
@Autowired public Module specificSerializers(ReverserResultSerializer reverserResultSerializer) {
SimpleModule serializerModule = new SimpleModule();
serializerModule.addSerializer(ReverserResult.class, reverserResultSerializer);
return serializerModule;
}
}
Я также подтвердил, что бин действительно присутствует в тесте. Поэтому я могу исключить, что контекст, созданный во время тестирования, отсутствует для загрузки 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, но он также не использовался. Интересно, если я пропускаю настройку (хотя я действительно пробовал много аннотаций ...) или я столкнулся с ошибкой. Я много занимался поиском в Google и SO, но ни одно из найденных решений не помогло. Кроме того, несколько человек на данный момент используют функции маршрутизатора:).
Любая помощь приветствуется!
ОБНОВЛЕНИЕ: Я пробовал также с 2.0.2.RELEASE и 2.1.0.BUILD-20180509. Результат всегда один и тот же.