Рубрики
Без рубрики

Ошибки преобразования Json с помощью Spring MockMvc

Пример странного поведения Spring MockMvc при сериализации/десериализации JSON

Автор оригинала: Marcin Piczkowski.

MockMvc-это класс Spring, используемый для модульного тестирования контроллеров без необходимости запуска сервера. Он имеет свободный API для подтверждения ответных сообщений. Например: для ответа JSON мы можем написать утверждения, подобные этому:

 this.mockMvc.perform(get("/test"))
                .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.value", is("Hello!")));

Под ним используется JSONPath .

Это хорошо работает для утверждений строковых значений, но может вести себя странно с числовыми значениями.

Вот пример:

При тестировании метода контроллера:

    public static final double VALUE = 0.07185454505642408;

...

    @GetMapping(value = "/test", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ResponseEntity get() {
        Dto dto = new Dto();
        dto.setValue(VALUE);
        return new ResponseEntity(dto, HttpStatus.OK);
    }

использование теста:

@RunWith(SpringRunner.class)
@WebMvcTest(ExampleController.class)
public class ExampleControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void should_get_metadata_when_video_processed() throws Exception {
        this.mockMvc.perform(get("/test"))
                .andDo(print())
                .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.value", is(ExampleController.VALUE)));
    }

}

тест завершается неудачей с:

java.lang.AssertionError: JSON path "$.value"
Expected: is <0.07185454505642408>
     but: was <0.07185454505642408>
Expected :is <0.07185454505642408>
     
Actual   :<0.07185454505642408>

Ух ты! Оба напечатанных значения, ожидаемое и фактическое, одинаковы. Что происходит?

На самом деле проблема заключается в типе ожидаемого и фактического. Ожидаемое-это Двойной но на самом деле это Большая десятичная .

Я бы не узнал об этом, если бы не отладил его.

Причина в том, что MockMvc использует Json Smart JsonProvider для сериализации.

Когда значение невелико, например, для Long оно может быть уменьшено до целого числа, для BigDecimal – до двойного, то так работает JsonSmartJsonProvider .

Это приводит к неожиданным ситуациям, когда мы сериализуем значения определенного типа в JSON но он не может быть десериализован обратно в тот же числовой тип.

Что же тогда является решением?

Вместо этого можно использовать другой JsonProvider – JacksonJsonProvider , который является прогнозирующим, потому что вы можете настроить его так, чтобы он всегда десериализовывал числовые значения в длинные и двойные.

Жаль, что это не реализация по умолчанию, используемая в JSONPath.

Вот небольшой проект на Github с некоторыми тестами, демонстрирующими проблемы с JsonSmartJsonProvider и как их решить с помощью JacksonJsonProvider

В двух словах, решение простое. Вам нужно добавить эту конфигурацию при инициализации тестов:

        final ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.enable(DeserializationFeature.USE_LONG_FOR_INTS);
        objectMapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);

        Configuration.setDefaults(new Configuration.Defaults() {

            private final JsonProvider jsonProvider = new JacksonJsonProvider(objectMapper);
            private final MappingProvider mappingProvider = new JacksonMappingProvider(objectMapper);

            @Override
            public JsonProvider jsonProvider() {
                return jsonProvider;
            }

            @Override
            public MappingProvider mappingProvider() {
                return mappingProvider;
            }

            @Override
            public Set

Установив Характеристика десериализации вы получаете целочисленные значения, десериализованные всегда в Long и плавающие всегда в Большая десятичная .

Надеюсь, это поможет вам сэкономить время на решении странных ошибок, с которыми я столкнулся.

Оригинал: “https://www.codementor.io/@marcinpiczkowski/json-conversion-errors-with-spring-mockmvc-o2vmtb42y”