You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LocalDateTime集成测试断言错误:toString与数据库秒数长度不一致

LocalDateTime集成测试断言错误:toString()输出与数据库存储秒数长度不一致

在做LocalDateTime集成测试时碰到断言错误,搞不懂为什么toString()输出的秒数长度和数据库存储的值不一样。具体错误信息如下:

java.lang.AssertionError: 1 expectation failed.
JSON path _embedded.positionsSnapshotDToes.linkTime doesn't match.
Expected: <[2022-11-09T10:01:03.152146400]>
Actual: [2022-11-09T10:01:03.152146]

我用JPA存储实体,对应的POJO字段定义:

@Column(name = "LINK_TIME")
private LocalDateTime linkTime;

测试代码如下:

@Test
shouldPassLinkTime()
{
        final LocalDateTime anyLinkTime = LocalDateTime.now();

        posSnapshotRepo.save(
                PositionsSnapshot.builder()
                        .linkTime(anyLinkTime)
                        .build()
        );

       SnapshotFilterDTO dto = SnapshotFilterDTO.builder()
                .build();

        given()
                .spec(correctCredentialsAndPortSpec)
                .log().ifValidationFails()
                .contentType("application/json")
                .body(MAPPER_HELPER.writeValueAsString(dto))
                .when()
                .post("service/unmatched")
                .then()
                .statusCode(200)
                .log().ifValidationFails()
                .and().body("_embedded.positionsSnapshotDToes.linkTime", equalTo(Arrays.asList(anyLinkTime.toString())))
                .and().body("page.totalPages", equalTo(1))
                .and().body("page.totalElements", equalTo(1))
                .and().body("page.number", equalTo(0));
}

问题根源

  1. 精度不匹配:LocalDateTime.now()生成的是纳秒级精度的时间(示例里的.152146400),但多数数据库(比如MySQL的DATETIME类型)只支持微秒级精度(最多6位小数,即.152146)。JPA存数据时会自动截断超出数据库精度的部分。
  2. 断言逻辑失误:测试里直接用原始的anyLinkTime.toString()(纳秒级)和数据库返回的截断后的值(微秒级)对比,自然会不一致。

解决办法

方法1:统一时间精度

  • 修改实体类字段注解,明确数据库字段的精度:
@Column(name = "LINK_TIME", columnDefinition = "DATETIME(6)") // 6位对应微秒级
private LocalDateTime linkTime;
  • 测试时生成微秒级精度的时间,避免多余的纳秒部分:
final LocalDateTime anyLinkTime = LocalDateTime.now().truncatedTo(ChronoUnit.MICROS);

方法2:用格式化工具统一对比

不要直接用toString(),用DateTimeFormatter把时间格式化为统一字符串后再断言:

// 定义统一格式化器
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME;

// 测试中格式化后对比
String expectedTime = FORMATTER.format(anyLinkTime.truncatedTo(ChronoUnit.MICROS));
// ...
.and().body("_embedded.positionsSnapshotDToes.linkTime", equalTo(Arrays.asList(expectedTime)))

方法3:自定义匹配器忽略精度差异

如果不想修改精度,写个自定义Hamcrest匹配器,只对比到微秒级:

.and().body("_embedded.positionsSnapshotDToes.linkTime", everyItem(matchesLocalDateTimeUpToMicros(anyLinkTime)))

自定义匹配器示例:

private Matcher<String> matchesLocalDateTimeUpToMicros(LocalDateTime expected) {
    return new TypeSafeMatcher<String>() {
        @Override
        protected boolean matchesSafely(String actualStr) {
            LocalDateTime actual = LocalDateTime.parse(actualStr);
            return expected.truncatedTo(ChronoUnit.MICROS).equals(actual);
        }

        @Override
        public void describeTo(Description description) {
            description.appendText("时间字符串微秒级匹配 ").appendValue(expected);
        }
    };
}

内容的提问来源于stack exchange,提问作者Ahmet Karakaya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 00:01:12