Зональное время преобразуется в UT C в тесте Spring Integration - PullRequest
2 голосов
/ 05 августа 2020

Я пытаюсь проверить, что мой контроллер реактивного отдыха передает правильные данные. Эти данные содержат поле ZonedDateTime, которое мне нужно сохранить. Однако при запросе к контроллеру отдыха с помощью WebTestClient моя проверка не выполняется, потому что полученное время внезапно оказывается в UT C.

@Data
public class SimpleData {
    ZonedDateTime zdt;
}

@RestController
class SimpleDataController {
    @Autowired SimpleDataService service;
    @GetMapping("/simple")
    List<SimpleData> getData() {
        return service.getTimes();
    }
}

@Service
class SimpleDataService {
    public static final SimpleData DATA = new SimpleData();
    static {
        DATA.setZdt(ZonedDateTime.now(ZoneId.of("Europe/Berlin")));
    }

    public List<SimpleData> getTimes() {
        return List.of(DATA);
    }
}
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@ActiveProfiles("test")
class ApplicationTests {
    @Test
    void simpleDataTest() {
        List<SimpleData> fromRest = WebTestClient.bindToServer().baseUrl("http://localhost:8080").build()
             .get().uri("/simple").exchange()
             .expectBodyList(SimpleData.class)
             .returnResult().getResponseBody();
        assertThat(fromRest).containsAll(Collections.singletonList(SimpleDataService.DATA));
    }
}

Это не удается с

Ожидание ArrayList: <[SimpleData (zdt = 2020-08-05T09: 30: 40.291415300Z [UTC])]>, чтобы содержать: <[SimpleData (zdt = 2020-08-05T11: 30: 40.291415300 + 02: 00 [Европа / Берлин ])]>, но не смог найти следующие элементы: <[SimpleData (zdt = 2020-08-05T11: 30: 40.291415300 + 02: 00 [Europe / Berlin])]>

Само время правильное - разница часовых поясов вычтена из поля часа - но, очевидно, оно не равнозначно. Как ни странно, если вы запрашиваете URL-адрес с помощью клиента, JSON содержит правильные данные:

[{"zdt": "2020-08-05T11: 44: 10.4740259 + 02: 00 "}]

Кажется, это TestWebClient преобразование времени.

Это задумано? Могу я как-нибудь изменить это поведение?

Ответы [ 2 ]

1 голос
/ 05 августа 2020

Я не мог уснуть, не получив решения этой проблемы. Итак, вы go! Рабочее решение вашей проблемы. :)

@JsonComponent
class ZonedDateTimeJsonSerializer extends JsonSerializer<ZonedDateTime> {
    static DateTimeFormatter formatter = DateTimeFormatter.ISO_ZONED_DATE_TIME;
    
    @Override
    public void serialize(ZonedDateTime zdt, JsonGenerator jsonGenerator, 
      SerializerProvider serializerProvider) throws IOException, 
      JsonProcessingException {
        jsonGenerator.writeString(zdt.format(formatter));
    }
}

@JsonComponent
class ZonedDateTimeJsonDeserializer extends JsonDeserializer<ZonedDateTime> {
    static DateTimeFormatter formatter = DateTimeFormatter.ISO_ZONED_DATE_TIME;

    @Override
    public ZonedDateTime deserialize(JsonParser p, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        return ZonedDateTime.parse(p.getValueAsString(),formatter);
    }
}

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@ActiveProfiles("test")
@AutoConfigureWebTestClient
class ApplicationTests {

    @Autowired
    private WebTestClient client; // important! as the @jsonComponent has to be picked up

    @Test
    void simpleDataTest() {
      List<SimpleData> fromRest = client.
         .get().uri("/simple").exchange()
         .expectBodyList(SimpleData.class)
         .returnResult().getResponseBody();
      assertThat(fromRest)
          .containsAll(singletonList(SimpleDataService.DATA));
   }
}
1 голос
/ 05 августа 2020

Таким образом, одного ADJUST_DATES_TO_CONTEXT_TIME_ZONE недостаточно, WebTestClient не следует создавать вручную, вместо этого следует использовать @AutoConfigureWebTestClient и автоматически подключать клиента.

    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
    @ActiveProfiles("test")
    @AutoConfigureWebTestClient
    class ApplicationTests {

        @Autowired
        private WebTestClient client;
    
        @Test
        void simpleDataTest() {
          List<SimpleData> fromRest = client.
             .get().uri("/simple").exchange()
             .expectBodyList(SimpleData.class)
             .returnResult().getResponseBody();
          assertThat(fromRest)
              .containsAll(singletonList(SimpleDataService.DATA));
       }
    }

application.properties

    spring.jackson.deserialization.ADJUST_DATES_TO_CONTEXT_TIME_ZONE = false
...