What's a Good Way to Overwrite Datetime.Now During Testing

What's a good way to overwrite DateTime.Now during testing?

My preference is to have classes that use time actually rely on an interface, such as

interface IClock
{
DateTime Now { get; }
}

With a concrete implementation

class SystemClock: IClock
{
DateTime Now { get { return DateTime.Now; } }
}

Then if you want, you can provide any other kind of clock you want for testing, such as

class StaticClock: IClock
{
DateTime Now { get { return new DateTime(2008, 09, 3, 9, 6, 13); } }
}

There may be some overhead in providing the clock to the class that relies on it, but that could be handled by any number of dependency injection solutions (using an Inversion of Control container, plain old constructor/setter injection, or even a Static Gateway Pattern).

Other mechanisms of delivering an object or method that provides desired times also work, but I think the key thing is to avoid resetting the system clock, as that's just going to introduce pain on other levels.

Also, using DateTime.Now and including it in your calculations doesn't just not feel right - it robs you of the ability to test particular times, for example if you discover a bug that only happens near a midnight boundary, or on Tuesdays. Using the current time won't allow you to test those scenarios. Or at least not whenever you want.

Unit Testing: DateTime.Now

The best strategy is to wrap the current time in an abstraction and inject that abstraction into the consumer.


Alternatively, you can also define a time abstraction as an Ambient Context:

public abstract class TimeProvider
{
private static TimeProvider current =
DefaultTimeProvider.Instance;

public static TimeProvider Current
{
get { return TimeProvider.current; }
set
{
if (value == null)
{
throw new ArgumentNullException("value");
}
TimeProvider.current = value;
}
}

public abstract DateTime UtcNow { get; }

public static void ResetToDefault()
{
TimeProvider.current = DefaultTimeProvider.Instance;
}
}

This will enable you to consume it like this:

var now = TimeProvider.Current.UtcNow;

In a unit test, you can replace TimeProvider.Current with a Test Double/Mock object. Example using Moq:

var timeMock = new Mock<TimeProvider>();
timeMock.SetupGet(tp => tp.UtcNow).Returns(new DateTime(2010, 3, 11));
TimeProvider.Current = timeMock.Object;

However, when unit testing with static state, always remember to tear down your fixture by calling TimeProvider.ResetToDefault().

Best way to change DateTime.now across all places

Basically, stop using DateTime.Now directly. Instead, introduce an abstraction of a clock (I typically call it IClock) that has a single operation of "get the current date and time" and inject that everywhere, just like any other dependency.

You can then use a simple implementation that delegates to DateTime.Now (or better, DateTime.UtcNow, I'd suggest) for production, and a fake implementation for testing.

That's the approach we strongly encourage in my NodaTime library - where we provide the interface and production/fake implementations for you.

Strategies for dealing with DateTime.Now in unit tests

Is it possible/advisable to try and mock the date?

Yes, not only that it is advisable but it is the only way to reliably unit test your code in isolation. Suppose that you wanted to test the following (meaningless) method:

public bool Foo()
{
return (DateTime.Now.DayOfWeek == DayOfWeek.Sunday);
}

It's more than obvious that you can't test it because it relies on a static method (the static Now property to be more precise). It's clear that components which are tightly coupled like this cannot be unit tested in isolation.

Now consider this improvement (separation of concerns with constructor DI):

private readonly Func<DateTime> _nowProvider;
public SomeClass(Func<DateTime> nowProvider)
{
_nowProvider = nowProvider;
}

public bool Foo()
{
return (_nowProvider().DayOfWeek == DayOfWeek.Sunday);
}

Now that's much better and easier to unit test. SomeClass no longer depends on a non-deterministic date. In the real application you would obviously instantiate SomeClass like this:

var s = new SomeClass(() => DateTime.Now);
s.Foo();

and in your unit test you will mock it so that you can verify both cases:

var subjectUnderTest = new SomeClass(() => new DateTime(2011, 1, 3));
var actual = subjectUnderTest.Foo();
// assertions, ...

Unit testing DateTime.Now

I'm not sure if passing some time provider to task constructor is a good idea.

It is a good idea. References to DateTime.Now are considered dependencies on global state and are discouraged from being used directly. About the constructor - it may be argued that doing this inside a constructor is a bad practice as well ("doing work inside constructors"), but that is a different topic.

The best practice for testability is to create a small wrapper interface to provide the current time which can be implemented against DateTime.Now or mocked for tests.

While some test frameworks like Microsoft Fakes are able to replace the DateTime.Now getter, this is complex to set up and maintain and should only be used when needing to test legacy code.

If you happen to already be using libraries like System.Reactive ("Rx.NET") or NodaTime, they already have abstractions over time ( IScheduler for rx, IClock in NodaTime).

Is there an easy way to stub out time.Now() globally during test?

With implementing a custom interface you are already on the right way. I take it you use the following advise from the golang nuts thread you've posted:


type Clock interface {
Now() time.Time
After(d time.Duration) <-chan time.Time
}

and provide a concrete implementation

type realClock struct{}
func (realClock) Now() time.Time { return time.Now() }
func (realClock) After(d time.Duration) <-chan time.Time { return time.After(d) }

and a testing implementation.


Original

Changing the system time while making tests (or in general) is a bad idea.
You don't know what depends on the system time while executing tests and you don't want to find out the hard way by spending days of debugging into that. Just don't do it.

There is also no way to shadow the time package globally and doing that would not do
anything more you couldn't do with the interface solution. You can write your own time package
which uses the standard library and provides a function to switch to a mock time library for
testing if it is the time object you need to pass around with the interface solution that is bothering you.

The best way to design and test your code would probably be to make as much code stateless as possible.
Split your functionality in testable, stateless parts. Testing these components separately is much easier then. Also, less side effects means that it is much easier to make the code run concurrently.



Related Topics



Leave a reply



Submit