Alex Rivera | Logout

Unit testing code that does date processing based on today's date

Asked 2009-02-19T13:27:28.623
24

When code processes dates based on the current date, testing should cover edge cases such as leap years as well as the more frequent month and year boundaries.

In our code we always get the current date deep down in our classes using DateTime.Now (.NET, in our case).

How can you unit test such code?

Is this where Dependency Injection becomes very useful?

Edit

This is a slight aside, but apparently the next version of Typemock will allow faking of DateTime.Now

https://blog.typemock.com/2009/05/mockingfaking-datetimenow-in-unit-tests.html

Edit
Report

2 Answers

21

In our code we always pull out the current date using DateTime.Now (.NET, in our case). How can you unit test such code?

This is a dependency, and a non-deterministic dependency at that. You need to divide the responsibility of the code up a little more.

Before:

  • There is some code that uses the current datetime to do X.

After:

  • There should be some code that is responsible for getting the current datetime.
  • There should be some code that uses a datetime to do X.

These two sets of code should not be dependent on each other.

This pattern of seperating dependencies works for other cases as well (database, filesystem, etc).

answered 2009-02-19T13:33:57.127
3
public interface ITimeProvider {
    DateTime Now { get; }
}

public class SystemTimeProvider : ITimeProvider {
    public virtual DateTime Now { get { return DateTime.Now; } }
}

public class MockTimeProvider : ITimeProvider {
    public virtual DateTime Now { get; set; }
}

public class ServiceThatDependsOnTime {
    protected virtual ITimeProvider { get; set; }
    public ServiceThatDependsOnTime(ITimeProvider timeProvider) {
        TimeProvider = timeProvider;
    }
    public virtual void DoSomeTimeDependentOperation() {
        var now = TimeProvider.Now;
        //use 'now' in some complex processing.
    }
}

[Test]
public virtual void TestTheService() {
    var time = new MockTimeProvider();
    time.Now = DateTime.Now.AddDays(-500);
    var service = new ServiceThatDependsOnTime(time);
    service.DoSomeTimeDependentOperation();
    //check that the service did it right.
}
answered 2009-02-19T13:41:19.463

Your Answer