System.currentTimeMillis() Returns Kotlin Springboot 应用程序中的 0L

System.currentTimeMillis() Returns 0L in Kotlin Springboot Application

我正在开发一个混合 Java 和 Kotlin 编写的 Springboot 应用程序。我们有休息控制器、服务和数据库存储库,它们都需要知道挂钟时间。

我们可以直接调用System.currentTimeMillis(),但是我们的一些单元测试需要模拟当前时间来测试依赖于时间的行为,所以我们创建了这个接口:

import java.time.OffsetDateTime;

public interface TimeService {

    long currentTimeMillis();

    OffsetDateTime nowUtc();

}

以及该接口的实现:

import java.time.OffsetDateTime;
import java.time.ZoneOffset;

public class SystemTimeService implements TimeService {

    @Override
    public long currentTimeMillis() {
        return System.currentTimeMillis();
    }

    @Override
    public OffsetDateTime nowUtc() {
        return OffsetDateTime.now(ZoneOffset.UTC);
    }
}

以及这个告诉 Springboot 如何创建接口实例的 bean:

@Bean
public TimeService timeService() {
    return new SystemTimeService();
}

现在,我们的代码可以使用 Springboot 来注入和使用 TimeService 的实例,如下所示:

@Service
class SomeService(
    private val timeService: TimeService
) {

    fun doSomethingWithTime() {
        val now = timeService.currentTimeMillis()

        // do something with now
    }
}

问题是有时候运行ning单元测试的时候,timeService.currentTimeMillis()returns0L,应该是不可能 .

这似乎只在我们 运行 整个测试套件时发生,并且在调试时发生的频率较低,所以我 认为 这是一个竞争条件,但我很难找到它。如果我用直接调用 System.currentTimeMillis() 来替换 timeService.currentTimeMillis() 的使用,我就无法重现问题。

是否有可能是 Springboot 破坏了这个 bean 的生命周期,以至于在我们不希望它出现的地方重新使用模拟?由于 Kotlin 处理线程和异步执行 suspended 函数的方式,注入的 bean 是否会超出范围?我在 JVM 中发现了错误吗?

如有任何想法或建议,我们将不胜感激。

我能够添加一些日志记录来确认我的 ApplicationContext 包含一个模拟,而我并没有预料到它。我找到了一个使用 @MockBean(TimeService::class) 创建模拟的测试,但它并没有自行清理。我在那个测试中添加了一个 @DirtiesContext 注释,它似乎已经解决了模拟问题。