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

Mockito模拟ZonedDateTime时withZoneSameInstant返回null问题

Mockito模拟ZonedDateTime.now()时withZoneSameInstant返回null的解决方案

在Java测试场景中,我需要用Mockito模拟ZonedDateTime.now()方法,同时通过MapStruct编写转换器实现ZonedDateTime到OffsetDateTime的转换。但测试时发现:调用zonedDateTime.withZoneSameInstant(ZoneOffset.UTC)始终返回null——尽管zonedDateTime本身是非空的。

尝试过直接调用zonedDateTime.toOffsetDateTime()能正常运行,但这种转换方式不符合规范,不是预期的实现方式。最终定位到是Mock配置的问题,通过在mockStatic时传入CALLS_REAL_METHODS参数解决了问题。

相关代码示例

MapStruct转换器

@Mapper(componentModel = "spring")
public interface DateTimeConverter {
    default OffsetDateTime zonedToOffset(ZonedDateTime zonedDateTime) {
        if (zonedDateTime == null) {
            return null;
        }
        return zonedDateTime.withZoneSameInstant(ZoneOffset.UTC).toOffsetDateTime();
    }
}

最初的Mock工具方法(存在问题)

public static void mockZonedDateTimeNow(ZonedDateTime fixedDateTime) {
    try (MockedStatic<ZonedDateTime> mockedZonedDateTime = Mockito.mockStatic(ZonedDateTime.class)) {
        mockedZonedDateTime.when(ZonedDateTime::now).thenReturn(fixedDateTime);
    }
}

测试方法

@Test
void testDateTimeConversion() {
    ZonedDateTime fixedTime = ZonedDateTime.of(2024, 5, 20, 10, 0, 0, 0, ZoneId.of("Asia/Shanghai"));
    mockZonedDateTimeNow(fixedTime);
    
    DateTimeConverter converter = Mappers.getMapper(DateTimeConverter.class);
    OffsetDateTime result = converter.zonedToOffset(fixedTime);
    // 最初此处result为null,因为withZoneSameInstant返回null
}

问题根源

Mockito默认对静态类做Mock时,会把该类所有方法都替换为Mock实现,包括ZonedDateTime的实例方法withZoneSameInstant。由于我们只显式Mock了now()静态方法,未对withZoneSameInstant做任何配置,调用该方法时就会返回默认的null值。

解决办法

在调用Mockito.mockStatic()时传入Mockito.CALLS_REAL_METHODS参数,指定未被显式Mock的方法执行真实逻辑。修改后的Mock工具方法如下:

public static void mockZonedDateTimeNow(ZonedDateTime fixedDateTime) {
    try (MockedStatic<ZonedDateTime> mockedZonedDateTime = Mockito.mockStatic(ZonedDateTime.class, Mockito.CALLS_REAL_METHODS)) {
        mockedZonedDateTime.when(ZonedDateTime::now).thenReturn(fixedDateTime);
    }
}

这样配置后,只有ZonedDateTime.now()会被Mock逻辑覆盖,其他实例方法(如withZoneSameInstant)会执行真实代码,就能正常返回转换后的ZonedDateTime对象,最终得到正确的OffsetDateTime结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 01:12:29