Home > General > “DateTime.Now” in unit tests

“DateTime.Now” in unit tests

Inspired by Ayende’s post about dealing with time in tests, I started using his implementation of SystemTime.Now().

public static class SystemTime
{
    public static Func<DateTime> Now = () => DateTime.Now;
}

We may use SystemTime.Now() anywhere in our code instead of DateTime.Now. This will allow us to control time in a deterministic fashion in order to keep our tests consistent. However, one of the downsides is that we have to remember to reset the time after each test.

[TestMethod]
public void DemoTest()
{
    SystemTime.Now = () => new DateTime(1970, 1, 1);
            
    // Test code...

    SystemTime.Now = () => DateTime.Now;
}

We can ease the pain by implementing this as part of the tear down process that runs after each test. I think that’s an acceptable solution, but I still prefer all my test code to be as close together as possible. The tear down process may also run for tests that don’t deal with SystemTime.Now(), so that’s extra overhead for nothing.

Instead, I decided to add a few additions to SystemTime:

public class SystemTime : IDisposable
{
    private static Func<DateTime> now = () => DateTime.Now;

    public static DateTime Now
    {
        get { return now(); }
    }

    private SystemTime()
    {
    }

    public static SystemTime Context(DateTime dateTime)
    {
        now = () => dateTime;
        return new SystemTime();
    }

    public void Dispose()
    {
        now = () => DateTime.Now;
    }
}

I changed the Now property to type DateTime instead of Func<DateTime> so that it more closely resembles DateTime.Now. Implementing IDisposable gives us an easy way to reset SystemTime.Now.

[TestMethod]
public void DemoTest()
{
    using (SystemTime.Context(new DateTime(1970, 1, 1)))
    {
        // Test code...
    }
}

To demonstrate, we can run this code:

Console.WriteLine(SystemTime.Now);

using (SystemTime.Context(new DateTime(1970, 1, 1)))
{
    Console.WriteLine(SystemTime.Now);
}

Console.WriteLine(SystemTime.Now);

The output is:

5/9/2012 2:21:08 AM
1/1/1970 12:00:00 AM
5/9/2012 2:21:08 AM
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: