Flat Time: Instant Unit Testing of Timer Based Logic

Andy Victors
4 min readJul 7, 2021

I love unit tests. I love that feeling of increased confidence that your software is working exactly as you expect it to work, as you add another test. Now at some point I would inevitably stumble upon piece of logic which uses timeouts or another timer-based behaviour. Technically you can create a unit tests even for this case — waiting defined period of time and checking result afterwards. This would work but is just plain inefficient to wait the real time period. You may want to decrease periods for testing but this requires more code and the flakiness will not cease to chase you.

Given kind of simplest logic we can have using timer — start the timer and expect the trigger to happen, the unit test could look like this:

It turns out there is a way to do it differently. After all, we are not interested in the time itself, it would be sufficient to know if expected event had happened or not. Thus by saying that existence of non-existence of events is equivalent to the timer logic, we can abstract the time by using classical way of decoupling things in a software — an interface.

We define the `TimeProvider` interface which is able to perform a task of calling us back after defined time, which is another way of defining timer functionality so we can use it instead of timer.

Then the `Standard` implementation of this interface which is used in productive code will indeed use timer or its replacement (as Handler in Android).

And here goes the magic: the unit test flavour of this interface will not use time or timer at all, it will immediately call us back so we can register the event is happened — thus we have just flattened the time. Look at the more concise, absolutely stable and incredibly fast implementation of the same unit test as before:

Now as we learned to control the time it is tempting not to stop here. And we should not, because the logic was really simple. How about a bit more complex case where timer can be stopped, so the event should not fire if the stop was requested before.

Clearly we need more magic and this time we are going to `freeze` the time.

Technically it means we can define desired flow of timer based events in a linear way and the let it to roll out in one moment. In a way we can now treat time as just another input to our logic and control it with the same easiness as we use integer values.

In the example below we start the timer but stop it before. The point in [frozen] time, where stop is called is defined by declaring explicitly how much time would have been passed to the moment.

Kotlin based implementation of FlatTimeProvider can be found here. It has some limitations as it does not support for example if triggered event will start another timer, however even in current implementation it works surprisingly well for the usual cases of timer usage.

Good luck with time manipulations!

--

--

Andy Victors

Professional App Development (Android, iOS, BLE, Bluetooth, IoT)