Mock Java Date/Time for Testing
Time mocking is a viable solution to avoiding current time inconveniences during testing, which can be accomplished by using the new Java 8 Date/Time API.
Join the DZone community and get the full member experience.Join For Free
Referencing the current date/time in your source code makes testing pretty difficult. You have to exclude such references from your assertions, which is not a trivial task to complete.
Time mocking is a viable solution to avoiding current time inconveniences during testing, which can be accomplished by using the new Java 8 Date/Time API (JSR 310).
For obtaining the current moment in time all related classes from the
java.time package have the static method
We will not consider the approach with mocking static methods due to its bad performance reputation.
If you look into the
now() method of any Java API classes you will find that the overridden method works with the system clock:
What we can do is create the wrapper class with all the necessary methods for the current time, plus an additional method for mocking time. For the sake of the demo, we will call it
Let's look into the wrapper class more closely:
- First of all, we remember the system clock and system timezone.
- Using method
userMockTime()we can override time with the fixed clock and provide the time zone.
- Using method
useSystemDefaultZoneClock()we can reset the clock and the timezone to the system defaults.
- All other methods use the provided clock instance.
So far so good, but there are two problems left in this approach:
useMockTime()method is too dangerous for the production code. What we want is to somehow eliminate the usage of that method in the source code.
- We need to enforce using the
Timeclass instead of the direct usage of the
One of the best solutions is the ArchUnit library.
It gives you the opportunity to control your architectural rules using unit tests. Let’s see how we can define our rules using the JUnit 5 engine (there is also an option to define the same rules for the JUnit 4 engine).
We will need to add the necessary dependency (Maven example):
And add rule descriptions in the unit test folder:
As a bonus, we can also restrict usage of the old Date/Time API:
In the case that you use an old library/framework that does not support a new Date/Time API, we can create an adapter class for this purpose. (Please note that exclusion of the adapter class is already defined in the previous rule):
As a final example for the demo, we will create a JUnit 5 extension that automatically mocks time for a predefined value, for instance: 01–04–2020 12:45 Europe/Kiev
Now let's imagine we have a simple method:
Then we can create a unit test:
The full source code of the example can be found here: GitHub repository
Published at DZone with permission of Dmytro Stepanyshchenko. See the original article here.
Opinions expressed by DZone contributors are their own.