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;
}
}