My previous post “Mocking the Current Time in C#” raised a few objections due to it’s use of a Static Façade that mirrors the underlying DateTime’s interface. Despite also disliking Singleton-like behaviour in general, I very occasionally find it acceptable [1]. In this instance reading the clock has no side-effects and the previous mocking technique is delightfully simple, but it’s not the only way. I have also worked on teams which prefer not to hide any dependencies behind static interfaces and in that situation I’ll adopt a more traditional mocking approach.
The Clock Object
The first thing to define is an interface for our Clock object:
public interface IClock
{
DateTime Now { get; }
}
Now we can define an implementation for the real clock that we’ll use in production:
public class RealTimeClock : IClock
{
public DateTime Now
{
get { return DateTime.Now; }
}
}
So now, instead of hitting the hidden Clock façade, we’ll make our dependency more explicit by passing it via the constructor [2]:
public class DateCalculator
{
public DateCalculator(IClock clock)
{
_clock = clock;
}
public int AgeToday(DateTime birthday)
{
. . .
}
private readonly IClock _clock;
}
Now we can make use of our clock in the real-world like this:
var clock = new RealTimeClock;
var calculator = new DateCalculator(clock);
. . .
var age = calculator.AgeToday(my.Birthday);
We can either hold onto the clock and calculator objects and reuse them (as they’re stateless) or recreate them each time. It’s likely that we won’t create them locally but will pass them down from somewhere above (as per “The PFA Papers”).
The Mock Object
Mocking the clock to test our date calculator is now as simple as writing any other test. In this example I’m defining a manual mock, but you may prefer to use a mocking framework instead [3].
public class FixedTimeClock : IClock
{
public FixedTimeClock(DateTime time)
{
_time = time;
}
public DateTime Now
{
get { return _time; }
}
private readonly DateTime _time;
}
[Test]
public age_is_number_of_years_since_birthday()
{
var today = new DateTime(2016, 6, 1);
var clock = new FixedTimeClock(today);
var calculator = new DateCalculator(clock);
var birthday = new DateTime(2000, 1, 1);
var age = calculator.AgeToday(birthday);
Assert.That(age, Is.EqualTo(16));
}
Defaulting the Clock
The purpose of doing this was to make the clock an externally controllable dependency, which is why we made it an explicit argument to the DateCalculator constructor. However, despite the protestations about not using a static façade, I’ve then seen developers be happy with overloading the constructor so that you can avoid passing the real clock around everywhere in production code:
public class DateCalculator{
// Only used in production
public DateCalculator()
: this(new RealTimeClock())
{ }
// Only used by unit tests
internal DateCalculator(IClock clock)
{ . . . }
public int AgeToday(DateTime birthday)
{ . . . }
private readonly IClock _clock;
}
Another variation on this is to make the constructor that takes an explicit clock “internal” to show that it’s essentially just used for testing. At this point I have to ask again what the original objection to the Static Façade approach was, because we’ve just hidden the dependency again – it’s now only visible in unit tests – which is effectively no different to the previous approach. If you prefer to be explicit then it should be to make the production code, not test code, more transparent.
[1] So maybe I was off-by-one in “The Application-Wide Diagnostic Log - the One Acceptable Global Object” and there are really two acceptable global objects :o).
[2] Sorry but I can’t bring myself to use that sensationalist term “DI”, see “Terminology Overdose”.
[3] Just be aware of how they behave when you don’t configure them properly, see “Mocking Framework Expectations”.
No comments:
Post a Comment