如何使用 OffsetDateTime 属性测试数据类的相等性?

Posted

技术标签:

【中文标题】如何使用 OffsetDateTime 属性测试数据类的相等性?【英文标题】:how to test equality of data class with OffsetDateTime attribute? 【发布时间】:2021-12-13 21:05:04 【问题描述】:

我在 DTO 和实体中有一个属性,定义如下:

val startDate: OffsetDateTime,

dto 有一个toEntity 方法:

data class SomeDTO(
  val id: Long? = null,
  val startDate: OffsetDateTime,
  ) 

    fun toEntity(): SomeEntity 
      return SomeEntity(
        id = id,
        startDate = startDate,
      )
    

还有一个控制器

@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())
  

我有一个失败的测试:

  @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)
    
  

coVerify 的测试失败,因为 startDate 不匹配:

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: -

在语义上,startDates 匹配,但时区不同。我想知道如何强制coVerifyOffsetDateTime 类型使用适当的语义比较,或者如何强制OffsetDateTime= 的内部格式?或者我们应该使用什么其他方法来验证 expectedToStore 值是否传递给 someService.save(...)

我可以使用withArgs,但它很麻烦:

coVerify 
  someService.save(withArg    
    assertThat(it.startDate).isEqualTo(expectedToStore.startDate)
    // other manual asserts
 )

【问题讨论】:

您能添加您要测试的代码吗?谢谢! @JoãoDias 我添加了正在测试的(琐碎的)控制器代码,还添加了withArgs 解决方法,这仍然太麻烦了 @Stuck 我试图让最小的复制运行,但您的代码中的某些内容没有对齐。您的 toEntity 函数需要一个不可为空的 Long 并且没有默认值,但是在您的实现和测试中,您没有将任何值作为参数传递。此外,该函数根本不使用参数userId。你会这么好心,把代码调整成可运行的吗? 【参考方案1】:

tl;dr

将此添加到您的application.properties

spring.jackson.deserialization.adjust-dates-to-context-time-zone=false

这样,偏移量将被反序列化为检索到而不是更改。


我创建了一个(稍作修改)复制存储库on GitHub。在 Controller 内部,dto.startDate 的值已经是 2021-04-22T22:00Z,因此是 UTC。

默认情况下,使用“Jackson”的序列化库在反序列化期间将所有偏移量对齐到相同的配置偏移量。 使用的默认偏移量是 +00:00Z,类似于 UTC。

您可以通过属性spring.jackson.deserialization.adjust-dates-to-context-time-zone=true false 启用/禁用此行为,并使用spring.jackson.time-zone=<timezone> 设置时区

或者,您可以在反序列化期间强制将偏移量与其他时区对齐:

spring.jackson.time-zone=Europe/Berlin

这样,偏移量将与时区Europe/Berlin对齐。

【讨论】:

以上是关于如何使用 OffsetDateTime 属性测试数据类的相等性?的主要内容,如果未能解决你的问题,请参考以下文章

H2 数据库 - Java 的 OffsetDateTime 和 h2 类型之间的映射

在 Spring Boot 和 MongoDB 中使用 OffsetDateTime 会导致 MappingException

当时间需要在本地时间保持不变时,在 Java 中使用 OffsetDateTime 处理夏令时,而不管 DST

Spring Boot Rest - OffsetDateTime 作为浮点数返回

为啥 OffsetDateTime 序列化/反序列化结果有差异?

《日期与时间》第7节:ZonedDateTime与OffsetDateTime