Every time I see a Instant.now() / new Date() / something that creates a date based on the current time
I tremble. How do you expect to test that in a simple / coherent / easy to follow way?
When I see that code, I usually see tests using now() + duration to check that everything works. So that the test is not the same when run today than when run tomorrow.
Wouldn't it better to be able to "fix" the time and test your code with exact values of times/periods as well?
So that I've fighting in my team in order that everyone uses a ClockProvider to get the "current" time. That way I can instance my own ClockProvider in unit tests and I can override the default ClockProvider of my application in integration tests.
The former is pretty easy to understand, so that I'm not writing an example of that. This is an example of the latter.
For instance, my application would look like this:
@SpringBootApplication
public class BookingApplication extends AbstractAnemoneApplication {
@Bean
@ConditionalOnMissingBean(ClockProvider.class) // to allow tests to overwrite it
public ClockProvider getClockProvider() {
return () -> Clock.systemDefaultZone();
}
// An example of method using ClockProvider
boolean isItJanuary(@Nonnull ClockProvider clockProvider) {
return clockProvider.getClock().instant().atZone(UTC).getMonth() == Month.JANUARY;
}
And my IT tests:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {
FixingClockConfiguration.class, BookingsApplication.class})
@ExtendWith(SpringExtension.class)
public class BookingsApplicationIT {
@TestConfiguration
static class FixingClockConfiguration {
@Bean
public ClockProvider getClockProvider() {
ZonedDateTime fixedInstant = ZonedDateTime.of(2019, 04, 15, 14, 00, 00, 00, UTC);
return () -> Clock.fixed(fixedInstant.toInstant(), fixedInstant.getZone());
}
}
// ... your tests based on that date
}
Top comments (1)
very elegant solution with a conditional bean and provider - for a simple solution, you can also use the
now()
variants which accept ajava.time.Clock
as described in baeldung.com/java-override-system-..., and then when constructing the bean, set the "real" clock in normal code, or a fixed clock for testing, just as you did in your example.