Unit testing date & time related objects

I was recently working on a scheduler object that relied on retrieving the current date and time to see if any tasks it had were due for execution, this presented a problem, how do you unit test an object that relies on the current date and time?

We could just make no changes to the object and instead make the unit tests highly dependant on the date and time it is ran on and in some cases it might be ok (although highly impractical and dangerous) however for a scheduler this is not feasible.

What we need can be solved by “introducing another level indirection” paraphrased from David Wheeler’s famous quote. What we can then do is setup an interface that can bring us back a DateTime:

public interface IDateTimeSource
{
 DateTime CurrentDateTime();
}

Now we can implement a real-time version that will be used most of the time:

internal class RealTimeDateTimeSource : IDateTimeSource
{
 public DateTime CurrentDateTime()
 {
 	return DateTime.Now;
 }
}

And also a mock version that in this case we can specify when it should start and it just ticks along representing time:

internal class MockDateTimeSource : IDateTimeSource
{
 DateTime providedDateTime;
 Thread realTimeThread;
 readonly object syncLock = new object();

	private DateTime ProvidedDateTime
 {
 	get
 	{
 		lock (syncLock)
 		{
 			return providedDateTime;
 		}
 	}
 	set
 	{
 		lock (syncLock)
 		{
 			providedDateTime = value;
 		}
 	}
 }

	public MockDateTimeSource(DateTime startAt)
 {
 	providedDateTime = startAt;

		realTimeThread = new Thread(delegate()
 	{
 		while (true)
 		{
 			ProvidedDateTime = ProvidedDateTime.AddSeconds(1);
 			Console.WriteLine(providedDateTime.ToString("hh:mm:ss"));
 			Thread.Sleep(1000);
 		}
 	}
 	);
 	realTimeThread.IsBackground = true;
 	realTimeThread.Start();
 }

	public DateTime CurrentDateTime()
 {
 	return ProvidedDateTime;
 }

}

The locking is to ensure that the write in the background thread and the read in the calling thread take place see http://www.yoda.arachsys.com/csharp/threads/volatility.shtml for more info.Now we need to provide the object with the version to use as it’s date and time source, we can do this numerous ways here is an example using constructor injection:

public Scheduler() : this(new RealTimeDateTimeSource())
{
}

public Scheduler(IDateTimeSource dateTimeSource)
{
 this.dateTimeSource = dateTimeSource;
 Initialize();
}

The parameter-less constructor will be used in most cases however for unit testing we can provide the mock version so that our tests can be decoupled from the date and time they are ran.If you wanted to provide extra security so that when the code goes into production users of the scheduler object can never pass in an IDateTimeSource you could change the constructors and also add a conditional preprocessor directive so that the release build never includes the testing constructor.

Advertisements

4 thoughts on “Unit testing date & time related objects

  1. Woah! I’m really enjoying the template/theme of this blog.
    It’s simple, yet effective. A lot of times it’s hard to get that “perfect balance” between usability and appearance.

    I must say you have done a amazing job with this.

    Additionally, the blog loads super fast for me on Internet explorer.
    Superb Blog!

Comments are closed.