【问题标题】:how to test equality of data class with OffsetDateTime attribute?如何使用 OffsetDateTime 属性测试数据类的相等性?
【发布时间】: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。你会这么好心,把代码调整成可运行的吗?

标签: spring spring-boot kotlin spring-mvc mockk


【解决方案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对齐。

【讨论】:

    猜你喜欢
    • 2011-12-24
    • 2013-01-22
    • 2021-09-24
    • 1970-01-01
    • 1970-01-01
    • 2019-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多