views:

664

answers:

8

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

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

+2  A: 

you could make a mockobject that simulates the DateTime.Now

here is article with an example where DateTime.Now is being mocked: http://geekswithblogs.net/AzamSharp/archive/2008/04/27/121695.aspx

Natrium
+6  A: 

Always put the core date processing logic (which is, in my experience, usually easy to isolate for this purpose) into separate methods that take the date as a parameter.

Then, in your production code you can call those and give them the current date as parameter, and still test edge cases to your heart's content in unit tests.

BTW, I've found it quite crucial to test date logic very intensivel for edge cases. It eliminates (possibly catastrophic, ref. Zune) bugs that you'd never have found otherwise. Apart from the ones you mentioned, daylight savings time switches can also be problematic.

Michael Borgwardt
DST is much _more_ problematic in my experience...
mavnn
+7  A: 

Using DI for injecting "Current Date & Time" is surely an overkill. I'd rather refactor the code to operate on arbitrary date. That is, I'd change function calculateRevenue() to function calculateRevenueOn(datetime date). This is much easier to test and use in case you need calculation for some dates other than current.

Anton Gogolev
IMO, accepting a parameter is a form of DI - and also probably the right fit for this problem. +1
David B
Technically, passing a parameter is not a form of DI (as per Martin Fowler: http://en.wikipedia.org/wiki/Dependency_injection#Types)
Anton Gogolev
Sorry, I was thinking about passing a Func<DateTime>. You are, of course, correct. Feel free to remove this discussion.
David B
+7  A: 

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).

David B
A: 

Dependency injection can be a solution for this, yes.

What you will do is create, for example, an IDateTimeProvider interface with a method: GetDate(). In your production-code class you will implement return DateTime.Now.

When unit testing, as Natrium suggested, you can then replace this with a mock object, one that returns a certain date to test on.

Gerrie Schenck
+2  A: 

You already gave the answer. You can write a small wrapper class around datetime functions that you can then inject in the classes that need to get the current date. Replacing DateTime.Now with a call to your wrapper object.

In your tests you can then inject a stub or mock object that gives you the date you need.

Another solution might be, depending on how your code works, just pass the date as a parameter instead of burying calls to datetime.Now. This makes your code a bit more reusable because it can work on more than the current date

Mendelt
+2  A: 

I've used the very pragmatic approach discussed by Oren Eini (aka Ayende Rahien) in his blogspots Dealing with time in tests.

There is a static class like this:

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

you're code becomes:

Entity.LastChange = SystemTime.Now();

And your test would become:

SystemTime.Now = () => new DateTime(2000,1,1);
repository.ResetFailures(failedMsgs); 
SystemTime.Now = () => new DateTime(2000,1,2);
var msgs = repository.GetAllReadyMessages(); 
Assert.AreEqual(2, msgs.Length);
Davy Landman
+1  A: 
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.
}
Justice