Kotlin SpringBoot应用TimeService#currentTimeMillis偶返0L问题求助
问题根因预判
90%以上概率是测试上下文缓存导致的Mock实例残留,可直接排除JVM Bug,大概率也不是Kotlin协程本身的问题。
排查思路
1. 优先排查测试Mock残留问题
- 全量测试套件运行时Spring会默认缓存测试上下文,如果某一个测试类使用了
@MockBean对TimeService做过模拟,并且配置了when(timeService.currentTimeMillis()).thenReturn(0L),测试结束后没有重置Mock、也没有标记上下文脏数据,缓存的脏上下文会被后续测试复用,导致非预期的Mock实例被注入到业务Bean中。 - 快速验证:给出现问题的测试类加上
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD),如果问题不再复现,即可定位为上下文污染问题。 - 根治方案:所有使用
@MockBean修改TimeService的测试类统一加上@DirtiesContext,或者测试执行完成后调用Mockito.reset(timeService)清理Mock规则。
2. 检查TimeService Bean的配置是否存在冲突
- 检查是否有测试类中的
@TestConfiguration额外定义了TimeService的Bean,且没有做条件限制,导致正常的SystemTimeService被覆盖。 - 检查TimeService的Bean是否加了
@Lazy、@RequestScope等特殊注解,如果代理实例在未完成初始化的场景下被调用,可能出现返回默认值的异常。 - 可在SystemTimeService的
currentTimeMillis方法中增加日志,打印实例哈希码和返回值,出现0L时对比哈希码即可确认是否为正确的SystemTimeService实例。
3. 协程异步场景排查
- 如果调用
timeService.currentTimeMillis()的逻辑在suspend函数、@Async异步方法中执行,检查是否存在自定义协程上下文传递时错误替换了Bean实例的场景,不过这类场景导致返回0L的概率极低,可在确认前两个排查方向无问题后再验证。
内容的提问来源于stack exchange,提问作者MusikPolice
相关产品推荐
相关产品推荐

