Software Development

Mock Around the Clock

When I produced System Stubs I attempted, and failed, to produce a mock implementation for the system clock.

It’s very convenient in production code to create a variable containing something like DateTime.now() and then perform time calculations between that instant and some other date.

How Do We Mock It For Testing?

I’m going to attempt to surprise you by telling you that, in my experience, most attempts to mock the above in Java, end in failure.

In other languages, it can be possible to inject some alternative behaviour into the global get function for the current time. When that’s possible, then it’s a great solution.

At some point, I may figure out how to intercept the calls to System.currentTimeMillis() in Java and produce the ClockMock I so want to produce… but until then:

Stop trying to mock the current time in Java with an abstraction!

Why Can’t I Mock Current Time?

You can.

But you just said…

I said don’t introduce an abstraction. Introducing a known time value into an algorithm that calculates time is ok. But introducing a wide-spread time getter abstraction is not.

Consider the following:

int getDriverAge(Date dateOfBirth, TimeGetter timeGetter) {
   return roundToWholeYears(daysSince(dateOfBirth, timeGetter));
}

int daysSince(Date date, TimeGetter timeGetter) {
   Date now = timeGetter.getNow();

   // return days between date and now
}

In the above example, the TimeGetter has spread through a couple of functions. How many other tiers above were there holding this abstraction of now() that’s only there so a test can replace it with a mock?

Whether it’s my made up TimeGetter or Java’s built in Clock or any other number of tricks, this pattern sucks. The ability to abstract time becomes a virus in the software.

Similarly, trying to use a global singleton that’s mockable creates a necessity to check that nobody’s bypassing MockableTime.now() with the real now() function.

So How Can We Test Time?

Two tricks.

  1. Use Fuzzy Assertions for time when doing grander tests – don’t be bothered by the exact time output if it’s not necessary/predictable in real life.
  2. Definitely test any algorithm that depends on real dates by ensuring that its public interface allows all date inputs (including now) to be passed in.

This means that the code that’s most low-level-implementation-ey should not itself call now() but should just process time data.

Slightly higher up, we know that code can safely pass now() down to lower level code, and we don’t need to worry about predicting the answer.

Our tests at a higher level can use fuzzy assertions that either check is this a time stamp or is this a time stamp within a certain range – so long as that doesn’t lead too much to Trial By Competitive Calculation.

TL;DR

Creating an abstraction for something as global and simple as time can create a virus throughout the entire codebase, where loads of modules suddenly need to know about something that’s really only a hook for testing.

Choosing your battles carefully can lead to low-level code not fetching the time itself, making it easier to test, and higher level code’s tests not worrying too much about precise times in results, because they’re already covered by lower level tests.

Published on Java Code Geeks with permission by Ashley Frieze, partner at our JCG program. See the original article here: Mock Around the Clock

Opinions expressed by Java Code Geeks contributors are their own.

Ashley Frieze

Software developer, stand-up comedian, musician, writer, jolly big cheer-monkey, skeptical thinker, Doctor Who fan, lover of fine sounds
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Azuaron
3 years ago

You should really just be using a DI framework to inject Clock where needed.

Ashley Frieze
Ashley Frieze
3 years ago
Reply to  Azuaron

You can. We were doing that in the code that inspired this article. The problem is that time is such a global, that having to make every component that consumes time hold a reference to the time object… it sucks. We can do the same with environment variables, and other system constants, but then you end up with a series of components that all hold half a dozen references to system resource readers before they even have any features of their own. It’s a solution. It’s a common one, but my view is that it’s noise in the code, almost… Read more »

Back to top button