Code that relies on timers is tricky to unit test. You have to check the functionality of your code and ensure there is the correct synchronisation between the test and the timer thread.
Unless special measures are taken, exceptions thrown from production code will be swallowed by the timer thread and when this happens the unit test fails with an ambiguous failure (usually a time-out or failed mock expectation).
You can be left in a situation where you have to choose between conservatively long time out values (that make your tests run slowly) or faster unreliable tests that have occasional failures.
Recently I’ve adopted a technique for dealing with these issues, by splitting the functional responsibilities of a class from its timing, so I can test them in isolation.
As an example, imagine you’ve got a HouseKeeper class that removes all the old transactions from a system. It uses a timer to trigger this behaviour every ten minutes. It might look something like this in Java 8:
How do you go about testing this? You certainly don’t want your tests to have to wait 10 minutes each time they start the HouseKeeper, before checking if the class removed any transactions.
You could make the timer duration configurable so that the unit test can reduce the timer period to something much shorter.
Now you can write a unit test that reduces the timer period to something more manageable and waits long enough for it to trigger.
This works, but it’s fragile because its based on timing. External factors like the load on the PC will affect when exactly the timer triggers and when the test fails it will be hard to see the cause of the failure (did the code fail or did we not wait long enough).
In addition, the wait slows the test suite down. You can probably tolerate a one second pause in the tests, but as you add more tests that rely on the HouseKeeper those pauses will soon add up.
Instead of these slow or unreliable tests you could do something different. Let’s create a Clock interface that you can use to represent different types of timers.
You now update the HouseKeeper class to use an instance of this interface that is passed to its constructor.
The rest of the production code will supply the HouseKeeper class with an implementation of this interface that works just like before.
Now you can test the HouseKeeper class using a new implementation of Clock that lets you control when the time period elapses.
Here’s the overall picture.
The unit test now looks like this.
The Thread.sleep has gone so there’s no waiting around and the test is fast. More importantly, there’s no timer thread being run so if the test fails it must be because the functionality is wrong. Finally, any exceptions thrown from the HouseKeeper will be visible to the unit test, making debugging errors easier.
Of course, you’ll still want to exercise the timer set up code inside your integration and stress tests, but you can go forwards with confidence in the code’s core functionality.