Archive

Archive for the ‘Patterns’ Category

Testing DateTime.Now (and other things) with an Ambient Context

September 30, 2013 2 comments

One issue you’re likely to face while writing automated tests is that it can be tricky to check anything related to DateTimes, as they are typically accessed statically using:

var startTime = DateTime.Now;

The approach I’ve typically used is to create some kind of IDateProvider interface, and supply that as a dependency as needed using Dependency Injection.  However, with things used throughout a system like DateTime can be, this becomes quite a chore and make the code more complex with an ever-increasing list of dependencies.

One of the great tips given by Ian Russell at an Agile Yorkshire meetup recently was to use the Ambient Context pattern in this, and other similar situations.

Note: I didn’t write the code below, I found it in various places online, particularly this Stack Overflow question by Mark Seemann, author of Dependency Injection in .Net.  I was having trouble finding the details online, which is why I’ve posted them here.

So, to take full control of DateTime.Now, you need an abstract TimeProvider:

public abstract class TimeProvider {
   private static TimeProvider current =
   DefaultTimeProvider.Instance;

   public static TimeProvider Current {
      get { return TimeProvider.current; }
      set {
         if (value == null) {
            throw new ArgumentNullException("value");
         }
         TimeProvider.current = value;
      }
   }

   public abstract DateTime UtcNow { get; }

   public static void ResetToDefault() {
      TimeProvider.current = DefaultTimeProvider.Instance;
   }
}

A concrete implementation used in your live system:

public class DefaultTimeProvider : TimeProvider {
   private readonly static DefaultTimeProvider instance = 
      new DefaultTimeProvider();

   private DefaultTimeProvider() { }

   public override DateTime UtcNow {
      get { return DateTime.UtcNow; }
   }

   public static DefaultTimeProvider Instance {
      get { return DefaultTimeProvider.instance; }
   }
}

And a mock for testing, for example here set up with Rhino.Mocks:

var fakeTimeProvider = MockRepository.GenerateStub();
fakeTimeProvider.Expect(x => x.UtcNow).Repeat.Once()
   .Return(new DateTime(1999, 12, 31, 11, 59, 59, 999));
fakeTimeProvider.Expect(x => x.UtcNow).Repeat.Once()
   .Return(new DateTime(2000, 1, 1, 0, 0, 0, 0));

For this to work, instead of calling dateTime.Now (or DateTime.UtcNow as we’re using here) from your code, you need to call:

var startTime = TimeProvider.Current.UtcNow;

One last thing – don’t forget to reset the provider after you mock it out, otherwise your mock will remain as the time provider:

[TestCleanup]
public void TearDown() {
   TimeProvider.ResetToDefault();
}

As suggested in the title, this can be used for things other than DateTime, but that’s the only place I’ve tried it so far.

Happy testing!

Advertisements
Categories: Patterns, TDD, Unit Testing