Tengo un atributo en un DTO y una Entidad definidos así:
val startDate: OffsetDateTime, El dto tiene un método toEntity :
data class SomeDTO( val id: Long? = null, val startDate: OffsetDateTime, ) { fun toEntity(): SomeEntity { return SomeEntity( id = id, startDate = startDate, ) } }y un controlador
@RestController @RequestMapping("/some/api") class SomeController( private val someService: SomeService, ) { @PostMapping("/new") @ResponseStatus(HttpStatus.CREATED) suspend fun create(@RequestBody dto: SomeDTO): SomeEntity { return someService.save(dto.toEntity()) } }Y tengo una prueba fallida:
@Test fun `create Ok`() { val expectedId = 123L val zoneId = ZoneId.of("Europe/Berlin") val dto = SomeDTO( id = null, startDate = LocalDate.of(2021, 4, 23) .atStartOfDay(zoneId).toOffsetDateTime(), ) val expectedToStore = dto.toEntity() val stored = expectedToStore.copy(id = expectedId) coEvery { someService.save(any()) } returns stored client .post() .uri("/some/api/new") .contentType(MediaType.APPLICATION_JSON) .bodyValue(dto) .exchange() .expectStatus().isCreated .expectBody() .jsonPath("$.id").isEqualTo(expectedId) coVerify { someService.save(expectedToStore) } } La prueba falla para coVerify porque la fecha de startDate no coincide:
Verification failed: ... ... arguments are not matching: [0]: argument: SomeEntity(id=null, startDate=2021-04-22T22:00Z), matcher: eq(SomeEntity(id=null, startDate=2021-04-23T00:00+02:00)), result: - Semánticamente, startDate coincide, pero la zona horaria es diferente. Me pregunto cómo puedo hacer cumplir coVerify para usar una comparación semántica adecuada para el tipo OffsetDateTime o cómo puedo hacer cumplir el formato interno de OffsetDateTime =? ¿O qué otro enfoque deberíamos usar para verificar expectedToStore el valor de expectToStore se pasa a someService.save(...) ?
Podría usar withArgs pero es engorroso:
coVerify { someService.save(withArg { assertThat(it.startDate).isEqualTo(expectedToStore.startDate) // other manual asserts }) }tl; dr
Agregue esto a su application.properties :
spring.jackson.deserialization.adjust-dates-to-context-time-zone=falseDe esta manera, el desplazamiento se deserializará como recuperado y no alterado.
Creé un repositorio de reproducción (ligeramente modificado)en GitHub . Dentro del controlador, el valor de dto.startDate ya es 2021-04-22T22:00Z , por lo tanto, en UTC.
De forma predeterminada, la biblioteca de serialización utilizada "Jackson" alinea todos los desplazamientos durante la deserialización con el mismo desplazamiento configurado. El desplazamiento predeterminado utilizado es +00:00 o Z , que se asemeja a UTC.
Puede habilitar/deshabilitar este comportamiento sobre la propiedad spring.jackson.deserialization.adjust-dates-to-context-time-zone={true false} y establecer la zona horaria con spring.jackson.time-zone=<timezone>
Alternativamente, puede forzar la alineación del desplazamiento con otra zona horaria durante la deserialización:
spring.jackson.time-zone=Europe/Berlin De esta forma, el desplazamiento estará alineado con la zona horaria Europe/Berlin .