« Testing, robustness and checked exceptions | Main | Working in Chiswick »

Testing with a Clock

I needed an object that holds information about automated builds called BuildTime*. Every Build being built will need to know what time the next build is at, what the build interval is and so on. Testing this was looking tricky since it started to involve:

  • fooling around with Date, Calendar objects,
  • taking checkpoints against the System.currentTimeMillis call and trying to reason backwards from them,
  • sleep()ing while the clock moved forward,
  • examing printouts of Dates.

The last two did it for me. There's no need for real time or high-precision clocks when it comes to an automated build. A granularity of seconds or even minutes is fine, yet there's no way I'm putting the tests to sleep() and waiting for them to finish. And we all know that reading printouts defeats the purpose of unit testing.

So eventually I threw a Clock class together and allowed the BuildTime object to take a Clock object as a constructor argument. The Clock object itself is very simple, here's the interface:

public interface Clock
  void synchronize();
  void wind( long much );
  void unwind( long much );
  void unwindToTheEpoch();
  long currentTimeMillis();
  long currentTimeSeconds();
  Date currentDate();
  Date getTodayZeroHundred();

Clock uses System.currentTimeMillis as a millisecond counter for application time instead of for the system time - the Clock determines system time for its client via an offset which is set using wind() and unwind() and synchronize().

In the time I've been using it, I've found the Clock to be valuable for playing time travel with the code. Hourly or daily build cycles can be tested by making a single method call to change the time, without having to wait that length of time to pass. It's also good for checkpointing against a known time and testing against intervals. For example the getToday() call returns a Date set to zeroHundred hours today, which can used to set the Clock to that time.

I'm starting to think that this may be a more generally useful idiom useful for testing asynchronous code - a lot of what I do in work involves designing and building messaging systems. These are not always easy to test automatically unless you're willing to hang around for things to kick off - notably for reliability and retry mechanisms.

The secret to testing asynchronous code seems to be making application time logical instead of physical. I think perhaps the reason testing asynchronous code is considered hard is because time is controlled by the operating system and not the software application, so the application developer has to hand around for the OS to catch up.

I can't imagine I'm the only person that is manipulating time in this way for testing - and if it's useful I'm thinking someone else has probably written a 'real' Clock . So, does anyone else have this idiom?

* By the way, if you're wondering why I don't use Cruisecontrol or Anthill, that's easy. I did. I found them sufficiently complicated, fidgety to set up, overly abstracted away from Ant, and insufficiently abstracted away from reporting, that I decided to go ahead write my own. I want to see how simple the automated build process can be once the decision not to use at or cron is made. My guess was that all you needed to stunt the framework was a build config file, a couple of daemons, timing logic, and a plugin hook for reporting. And that seems to be the way things are working out.

August 31, 2003 08:39 PM


(September 3, 2003 07:58 PM #)

http://mentifex.virtualentity.com/variable.html#t -- time "t" needs implementing in artificial minds. Look ye to it :-)

Robert Blum
(September 4, 2003 01:24 PM #)

It's actually a fairly common pattern in the world of computer games. Especially since the world has fallen in love with slow-motion/matrix-style effects.

It's usually taken one step further and becomes a hierarchy of clocks so you can slow down subsystems in relation to a master clock.

What I really want to know though is: Are you going to share your build system with the world? :)

- Robert

Trackback Pings

TrackBack URL for this entry: