In some systems you sometimes need to record date or timestamp of given action. Good example could be comments system, where each comment has timestamp:
In our experiment we will perform two test cases:
- comment created at given time should have given timestamp
- second comment, created one after 1 second should have proper proper timestamp.
So how can we manipulate time in unit test?
Inject time provider to system under test
That’s probably the most desirable way to achieve testability of system under test – using dependency inversion. In this particular case, we inject current time provider to CommentsInteractor via constructor:
Each provideTime() invocation will return current time in milliseconds.
Test becomes fairly simple – current time is provided via function passed in constructor – we can put any value we want and make assertions based on given fixed time:
Joda Time
In Android world, where developers are stuck to Java 8 (and below API 26 there is no proper java.time support), there is tendency to use JodaTime as base date and time manipulation library.
When there is no option to inject time provider or refactoring the whole class is no worth it, you may decide to use helper methods from Joda Time to achieve testable time-based code:
setCurrentMillisFixed() in Joda Time
With Joda Time we can use static method setCurrentTimeMillisFixed(), which will tell Joda objects to always return given value.
Provide fake time with MillisProvider in Joda Time
According to documentation:
setCurrentMillisProvider(MillisProvider millisProvider)
* Sets the provider of the current time to class specified.
* This method changes the behaviour of currentTimeMillis().
* Whenever the current time is queried, the specified class will be called.
If we want to advance time in test, we could always use several setCurrentMillisFixed calls, nevertheless there exists more fluent method – set setCurrentMillisProvider:
We can also extract millis provider configuration to external function and implement our own mechanism to manipulate time in tests:
And refactor test case to use our new mechanism:
With this method we end up with DSL-like test code which separates what from how. Other tests may now use interactiveTime function as long as there is JodaTime used under the hood.
What are the options for testing time based code?
- inject time providers directly into system under test
- use library such as JodaTime which allows changing time providers in runtime
- use fixed time @Rules in JUnit4 or @Extension in JUnit5
- mock static system methods with Mockk, or tools like PowerMock