TDD: Thoughts on using a clock in tests
A few months ago Uncle Bob wrote a post about TDD where he suggested that he preferred to use hand created stubs in his tests wherever possible and only resorted to using a Mockito created stub as a last resort.
I wrote previously about my thoughts of where to use each of the two approaches and one example of where hand written stubs seems to make sense is the clock.
I wonder if this ties in with J.B. Rainsberger’s theory of irrelevant details in the tests which make use of it.
We would typically define an interface and stub version of the clock like so:
public interface IClock
{
DateTime Now();
}
public class ControlledClock : IClock
{
private readonly DateTime dateTime;
public ControlledClock(DateTime dateTime)
{
this.dateTime = dateTime;
}
public DateTime Now()
{
return dateTime;
}
}
I forgot about it to start with and was stubbing it out using Rhino Mocks but I realised that every single test needed something similar to the following code:
var theCurrentTime = new DateTime(2010, 1, 16);
var clock = MockRepository.GenerateStub<IClock>();
clock.Stub(c => c.Now()).Return(theCurrentTime);
We can extract out the creation of the first two lines into fields but the third line remains and typically that might end up being pushed into a setup method which is run before each test.
With a clock it’s maybe not such a big deal but with other dependencies from my experience it can become very difficult to follow where exactly the various return values are being setup.
When we use a hand written stub we only have to write the following code and then the date is controlled everywhere that calls 'Now()':
private readonly IClock clock = new ControlledClock(new DateTime(2010,1,16));
Following on from that my colleague Mike Wagg suggested the idea of creating extension methods on integers to allow us to fluently define values relative to the clock.
[Test]
public void ShouldShowFoosOlderThanToday()
{
var clock = new ControlledClock(new DateTime(2010,1,16));
var fooService = MockRepository.GenerateStub<IFooService>();
var fooFromYesterday = new Foo { Date = 1.DayBefore(clock) });
var aCollectionOfFoos = new List<Foo> { fooFromYesterday };
fooService.Stub(f => f.GetFoos()).Return(aCollectionOfFoos);
var oldFoos = new FooFinder(clock, fooService).GetFoosFromEarlierThanToday();
Assert.That(oldFoos.Count, Is.EqualTo(1));
// and so on
}
The extension method on integer would be like this:
public static class IntegerExtensions
{
public static DateTime DayBefore(this int value, IClock clock)
{
return clock.Now.Subtract(TimeSpan.FromDays(value));
}
}
It reads pretty well and seems more intention revealing than any other approaches I’ve tried out so I think I’ll be continuing to use this approach.
About the author
I'm currently working on short form content at ClickHouse. I publish short 5 minute videos showing how to solve data problems on YouTube @LearnDataWithMark. I previously worked on graph analytics at Neo4j, where I also co-authored the O'Reilly Graph Algorithms Book with Amy Hodler.