How to isolate DateTime.Now in unit testing

When writing unit tests for codes that is using DateTime.Now you will find yourself in a situation where you can’t automate functionality that are dependent on the time since the time is changing constantly. You are also not able to test for example that your codes work correctly for leap year or change of year, etc.

How would you test correctness of bellow simple example?

public bool IsIt2012
{
   get
   {
      return (DatemTime.Now.Year == 2012);
   }
}

The solution is to introduce a “wrapper” for DateTime.

public bool IsIt2012
{
   get
   {
      return (DatemTimeIsolator.Now.Year == 2012);
   }
}

Test for this property could look like this

[TestMethod()]
public void Class1_IsIt2012_CurrentYear2012_ExpectedTrue()
{
   using (DatemTimeIsolator.NowIs(new DateTime(2012, 12, 30)))
   {
      bool actual = new Class1().IsIt2012;
      Assert.AreEqual(true, actual);
   }
}
 
[TestMethod()]
public void Class1_IsIt2012_CurrentYear2011_ExpectedFalse()
{
   using (DatemTimeIsolator.NowIs(new DateTime(2011, 12, 30)))
   {                
      bool actual = new Class1().IsIt2012;
      Assert.AreEqual(false, actual);
   }
}

As we all know unit test should not have any side effect and always leave machine as found. That is here achieved by using a IDisposable pattern. In this way the original functionality of DateTImeIsolator is automatic reverted back after tested.

DateTImeIsolator.cs

public class DatemTimeIsolator : IDisposable
{
   private static DateTime changedNowDateTime;
   private static bool nowChanged;
 
   public static DateTime Now
   {
      get { return nowChanged ? changedNowDateTime : DateTime.Now; }
   }
 
   public static IDisposable NowIs(DateTime dateTime)
   {
      changedNowDateTime = dateTime;
      nowChanged = true;
      return new DatemTimeIsolator();
   }
 
   public void Dispose()
   {
      nowChanged = false;
   }
}

All of this could have been done by moles for example or by changing the API so it would be possible to inject different behavior into the code. But I prefer to make my code testable strait out of box with as few changes to the public API as possible, since it will make my code more robust.

Link to code:StaticClassIsolators

0.00 avg. rating (0% score) - 0 votes

About Peter Wibeck

Comments

One Response to “How to isolate DateTime.Now in unit testing”

Trackbacks

Check out what others are saying about this post...
  1. […] i wrote a blog post about isolating DateTime.Now with disposable pattern. Here is a little more advance example for the static method […]



Speak Your Mind

Tell us what you're thinking...
and oh, if you want a pic to show with your comment, go get a gravatar!

*