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.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in Design, Testing. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.lostechies.com/members/colinjack/default.aspx Colin jack

    Great stuff. Didn’t really Ayende had used that sort of solution but thats pretty much what I’ve started doing.

    My implementation was a bit differrent as I’ve used an IClock interface (with one member Now) with two implementations Clock and StubClock but Clock (your SystemClock) also has a static member that lets you replace the instance. Same idea just a slightly different implementation (not sure I explained it well, no matter).

    Only *slight* issue I’ve had is leaivng the DateTime in SystemClock behind in tests. My work around was to have a time_senstive_context_base and have it make sure we put back the real clock at the end. You doing something similiar?

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @colin

    I really haven’t had a problem so far – I do have a Reset() method to reset the Now back to DateTime.Now. But if I’m testing behavior that uses SystemTime.Now(), I’ll have to do something with it, or the test will fail. The only thing not resetting will do is affect other tests. It won’t affect debugging, running locally or production, since those run in different AppDomains.

  • nightshade427

    Isn’t SystemTime is just using a simplified serviceLocator type approach?

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @nightshade427

    Yep, exactly! It’s an assumption that _every_ dependency resolver needs to be through dependency injection. I think global dependencies like this one are prime candidates for service location.

  • nightshade427

    ya i would agree as well.

  • Nathan Alden

    Two reasons I would avoid the service locator approach:

    The first is that I have to remember to replace the delegate with the original one (() => DateTime.Now) in all my tests. Setting and relying on static things in tests often leads to hard-to-track-down test failures, or even false passes.

    The second is I actually prefer to know that my objects are relying on the system clock. Injecting ISystemClock into their constructors makes this obvious.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Nathan

    We wound up using SystemClock in our entities, and ISystemClock in DI-enabled services. I’ve never actually run into a test that fails because I forgot to reset SystemClock though, my tests always set up their own data.

  • Pingback: Pragmatic SOLID – Part 5 – The Dependency Inversion Principle | @GilesDMiddleton