Software Development

Testing Time

Oooh, it’s a nuisance when you write and write automated tests for code that’s supposed to depend on the current time. Stuff’s going to go wrong.

There are essentially two categories of problem:

  • The exact timestamps output are different, so are hard to unit test
  • Simulating timings, and events happening the right distance apart, is very hard in a test if you’re using the real clock

There are some good techniques we can use. For example, we can use a fuzzy assertion to prove that the output is in the right format, and not worry too much about the exact timestamp. Similar things may also be needed when the continuous integration server has a different perspective on things like daylight savings time, and we have timestamp formats to consider.

There are also some bad or just difficult techniques. I tried quite hard, while writing System Stubs, to have a clock mock. I hit so many problems with each technique I tried, that I decided not to persevere… That said, there are legends that it’s possible to mock the actual clock. I couldn’t get traction on it.

We can create an interface between our code and the clock, making time mockable. This, generally, allows us to control time, but it makes the real code a bit clunkier, since we now have to wire the clock object in all over the place.

Enter The Dual Channel Time Method

In Java Test Gadgets, I decided to write some code that can be used to measure activity on each thread that calls through it. This allows us to monitor the number of events on each thread and, especially, the concurrency reached during a test.

What I wanted to do was capture all the events during the test, and then do some maths on the events at the end. One method was something like this:

1
2
3
4
5
6
7
public void threadStartedAction(Thread t) {
   // remember the start time of the thread
}
 
public void threadEndedAction(Thread t) {
   // remember the end time
}

At the highest level, I wanted to run some scenarios where the actual timings against the system were quite a useful measure of success. So, 10 concurrent threads running over 100ms should all achieve an overlap and reach concurrency of 10. This needs real timings to prove itself.

However, when we got to the code which calculates the actual statistics, I wanted to be able to construct the various edge cases using plain old numbers, which meant I couldn’t contrive it with Thread.sleep called here and there in my test code.

I didn’t want to have to provide a MockClock object into my code, but there was an easy answer.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
public void threadStartedAction(Thread t) {
   threadStartedAction(t, System.currentTimeMillis());
}
 
public void threadStartedAction(Thread t, long atTime) {
   // remember the start time of the thread
}
 
public void threadEndedAction(Thread t) {
   threadEndedAction(t, System.currentTimeMillis());
}
 
public void threadEndedAction(Thread t, long atTime) {
   // remember the end time
}

The lower level code has two options for calling into it. We can provide no parameter for the current time, and get the actual clock, or we can call it and provide the time our code thinks it is.

This is a tiny amount of method overriding, predominantly to open the code up to its own unit tests, but it results in us being able to construct some easy to understand unit tests that can sequence time without any mocking or sleeping.

One thing to note about the tests I wrote is that for my own simplicity, I used times close to 0. This violated one of the rules of testing, which is to use realistic data. Had I not also tested with the actual clock at another tier, and had the scenarios been related to anything other than relative time, I should have tried to avoid this technique.

In a previous project, we had some real world bugs hiding on the other side of tests that used fake times, as the unit of time was not clearly agreed between different tiers of the system. This can be alleviated by using classes like LocalDateTime or Duration rather than long in cases where it might matter.

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

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.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button