SystemTime versus ISystemClock – dependencies revisited
Yes, it’s true, I’m a big fan of the Dependency Inversion Principle and Dependency Injection. Scandalous! But there are some situations where DI can make your classes…rather interesting.
In one recent example, we needed to model an Occupation. A person living at a certain location for a certain time period represented an Occupation. In this system, a person could have occupied many locations, so many Occupations will have end dates. However, the current Occupation won’t have an end date. It would look something like this:
public class Occupation { public DateTime StartDate { get; set; } public DateTime? EndDate { get; set; } }
Obviously there is some other information like Location. But suppose we now want to calculate the length of stay for a given Occupation. Things work well when the person doesn’t occupy that location any more, but what if they still live there? We’ll need to go off of the current date.
Which brings us to our first problem. In .NET, this would be mean a call to DateTime.Now. But to write unit tests around this behavior, we’ll need to supply dummy values for DateTime.Now. Which isn’t really possible.
One option we have is to build something like this:
public interface ISystemClock { DateTime GetCurrentTime(); }
Better, now we have a place to supply a substitute. But do we need to give the Occupation the ISystemClock? Do we pass in the ISystemClock in the LengthOfStay method? That’s a little awkward. Now callers have to have this dependency ready and available, as opposed to it being injected by an IoC container. What tends to happen is the ISystemClock dependency becomes a little weed in our system, invading lots of places we really didn’t intend, but we need it because something underneath needs it.
The benefits are we get to see the explicit dependency, but it’s rather annoying as it’s just a dumb wrapper around DateTime.Now. Which really isn’t a dependency on a type, but a function. DateTime.Now is a static function that does some work underneath to do whatever, but it’s a function that returns a DateTime.
That’s where Ayende’s SystemTime comes into play – it exposes DateTime.Now as an instance of a function, that can be replaced in tests:
public static class SystemTime { public static Func<DateTime> Now = () => DateTime.Now; }
If I want to replace SystemTime.Now in a test, it’s easy to do:
[Test] public void Should_calculate_length_of_stay_from_today_when_still_occupied() { var startDate = new DateTime(2008, 10, 1); SystemTime.Now = () => new DateTime(2008, 10, 5); var occupation = new Occupation {StartDate = startDate}; occupation.LengthOfStay().ShouldEqual(4); }
Or, if I want to take advantage of Closures, I can set SystemTime.Now to any function that returns a DateTime:
var startDate = new DateTime(2008, 10, 1); SystemTime.Now = () => startDate.AddDays(4);
I don’t have to worry about SystemTime.Now being replaced in production, as other tests would fail if it were replaced. But the aspect I like the most about this approach is it’s both testable and elegant. I don’t have to litter the codebase with a system clock dependency, or worse, a DateTime holding the current date. I also don’t need to create a stub just for testing. There are advantages to an explicit ISystemClock dependency, but it still seems strange that I have to introduce constructor dependencies on what is essentially a dependency on a function.