Is it safe to use DateTimeUtils.setCurrentMillisFixed in tests?

java, jodatime, junit, testng

Solution

You must ensure that `DateTimeUtils.setCurrentMillisSystem()` is invoked in the `tearDown` method. So that one test does not affect another. TestNG should invoke `tearDown` even if an exception occurs in your test.

I often prefer another way when I want to decouple a class from `System.currentTimeMillis();`. I introduce an interface `Clock` and one implementation `SystemClock` like this:

public interface Clock {
    public long getCurrentTimeMillis();
}

public class SystemClock implements Clock {
    public long getCurrentTimeMillis(){
        return System.currentTimeMillis();
    }
}

For the tests it is then easy to create a mock that either returns a fixed time on every invocation or a series of predefined times.

Some might argue that it is overengineering to introduce such an interface to decouple only one method and it would be a performance impact. But fortunately we have a JIT compiler and since JIT knows that only the `SystemClock` class is loaded it knows that no other implementation exist (at the moment). At this assumption it can just use inline method.

So I prefer to write code in the way it can be tested best.

EDIT

With Java 8 you might want to use the `Supplier<Long>` interface.

E.g. in your client code you can than use method references

public class SomeClass {
    private Supplier<Long> currentTimeMillisSupplier;

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

    SomeClass(Supplier<Long> currentTimeMillisSupplier){
        this.currentTimeMillisSupplier = currentTimeMillisSupplier;
    }
}

The default constructor is for 'normal' use, while the other package scoped constructor can be used for unit tests. Just place the test class in the same package.

You can also use the `Clock` interface, because it is a `@FunctionalInterface`.

public class SomeClass {
    private Clock clock;

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

    public SomeClass(Clock clock){
        this.clock = clock;
    }
}

Problem

In order to test time-dependent code it's good to use Virtual Clock Pattern The idea is that we pull current time not using `new Date`, but from a clock which can be mocked with virtual clock returning predefined fixed time. Now in Java we have JodaTime with `DateTime` class and which allows to set sample time with ``` DateTimeUtils.setCurrentMillisFixed(today.getMillis()); ``` And reset the fixed time to a system time with: ``` DateTimeUtils.setCurrentMillisSystem(); ``` Here is a good article on how to use it with TestNG. Now the question! How safe it's to use this technique with setUp and tearDown methods if it globally sets fixed time in global context for the time of running test. As long as I get it - it will only work as long as we don't have two concurrent tests with this technique running in the same environment in parallel.

Original source

Related problems