Los Techies : Blogs about software and anything tech!

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.

Kick It on DotNetKicks.com
Posted Nov 09 2008, 01:11 PM by bogardj
Filed under: ,

Comments

colinjack wrote re: SystemTime versus ISystemClock – dependencies revisited
on 11-09-2008 1:22 PM

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?

bogardj wrote re: SystemTime versus ISystemClock – dependencies revisited
on 11-09-2008 2:01 PM

@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 wrote re: SystemTime versus ISystemClock – dependencies revisited
on 11-09-2008 7:16 PM

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

bogardj wrote re: SystemTime versus ISystemClock – dependencies revisited
on 11-09-2008 8:09 PM

@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 wrote re: SystemTime versus ISystemClock – dependencies revisited
on 11-09-2008 9:30 PM

ya i would agree as well.

Dew Drop - November 10, 2008 | Alvin Ashcraft's Morning Dew wrote Dew Drop - November 10, 2008 | Alvin Ashcraft's Morning Dew
on 11-10-2008 6:08 AM

Pingback from  Dew Drop - November 10, 2008 | Alvin Ashcraft's Morning Dew

Dew Drop - November 10, 2008 | Alvin Ashcraft's Morning Dew wrote Dew Drop - November 10, 2008 | Alvin Ashcraft's Morning Dew
on 11-10-2008 6:08 AM

Pingback from  Dew Drop - November 10, 2008 | Alvin Ashcraft's Morning Dew

Development Wiki: Arhitectura wrote Development Wiki: Arhitectura
on 11-18-2008 3:18 AM

Pingback from  Development Wiki: Arhitectura

Jeremy D. Miller -- The Shade Tree Developer wrote "A" way of dealing with dates in automated tests
on 03-18-2009 12:14 AM

a a Dates are annoying in automated tests. You'll inevitably have all kinds of business rules like

Community Blogs wrote "A" way of dealing with dates in automated tests
on 03-18-2009 12:35 AM

a a Dates are annoying in automated tests. You'll inevitably have all kinds of business rules like

Jimmy Bogard wrote Willed and forced design
on 11-12-2009 9:32 PM

Roy Osherove, as a TypeMock employee, presents quite a dilemma from opinionated TDD blog posts simply

Add a Comment

(required)  
(optional)
(required)  
Remember Me?

Enter the numbers above:
Copyright Los Techies 2008, 2009. All rights reserved.
Powered by Community Server (Commercial Edition), by Telligent Systems