在测试中使用DateTimeUtils.setCurrentMillisFixed是否安全?

Vla*_*mir 19 java junit testng jodatime

为了测试与时间相关的代码,最好使用虚拟时钟模式

我们的想法是,我们不使用当前时间new Date,而是从可以用虚拟时钟模拟的时钟返回预定义的固定时间.

现在在Java中我们有JodaTime和DateTimeclass,它允许设置采样时间

DateTimeUtils.setCurrentMillisFixed(today.getMillis());
Run Code Online (Sandbox Code Playgroud)

并将固定时间重置为系统时间:

DateTimeUtils.setCurrentMillisSystem();
Run Code Online (Sandbox Code Playgroud)

这是一篇关于如何在TestNG中使用它的好文章.

现在的问题!

如果它在运行测试时全局设置全局上下文中的固定时间,那么将此技术用于setUp和tearDown方法是多么安全.只要我得到它 - 它只会工作,只要我们没有两个并发测试,这种技术在同一环境中并行运行.

Ren*_*ink 17

您必须确保DateTimeUtils.setCurrentMillisSystem()tearDown方法中调用它.这样一个测试不会影响另一个测试.tearDown即使测试中发生异常,TestNG也应该调用.

当我想要从一个类中解耦时,我常常喜欢另一种方式System.currentTimeMillis();.我介绍一个接口Clock和一个这样的实现SystemClock:

public interface Clock {
    public long getCurrentTimeMillis();
}

public class SystemClock implements Clock {
    public long getCurrentTimeMillis(){
        return System.currentTimeMillis();
    }
}
Run Code Online (Sandbox Code Playgroud)

对于测试,可以很容易地创建一个模拟,该模拟在每次调用或一系列预定义时间返回固定时间.

有些人可能认为引入这样的接口来解耦只有一种方法是过度工程,这会对性能产生影响.但幸运的是我们有一个JIT编译器,因为JIT知道只SystemClock加载了类,所以它知道没有其他实现(目前).在此假设下,它可以使用内联方法.

所以我更喜欢以最佳测试方式编写代码.

编辑

使用Java 8,您可能希望使用该Supplier<Long>接口.

例如,在您的客户端代码中,您可以使用方法引用

public class SomeClass {
    private Supplier<Long> currentTimeMillisSupplier;

    public SomeClass(){
         this(System::currentTimeMillis);
    }

    SomeClass(Supplier<Long> currentTimeMillisSupplier){
        this.currentTimeMillisSupplier = currentTimeMillisSupplier;
    }
}
Run Code Online (Sandbox Code Playgroud)

默认构造函数用于"正常"使用,而另一个包作用域构造函数可用于单元测试.只需将测试类放在同一个包中.

你也可以使用Clock界面,因为它是一个@FunctionalInterface.

public class SomeClass {
    private Clock clock;

    public SomeClass(){
         this(System::currentTimeMillis);
    }

    public SomeClass(Clock clock){
        this.clock = clock;
    }
}
Run Code Online (Sandbox Code Playgroud)