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
How to Embed Multiple Images in Email Body Using .Net
Starting a Process with Credentials from a Windows Service
ASP.NET MVC 4 C# Httppostedfilebase, How to Store File
How to Get the Local MAChine Name in C#
Why Doesn't Dictionary<Tkey, Tvalue> Support Null Key
Xml Error: There Are Multiple Root Elements
Creating Directories in a Ziparchive C# .Net 4.5
Ternary Operator Vb VS C#: Why Resolves Nothing to Zero
How to Confirm That Mail Has Been Delivered or Not
Task<> Does Not Contain a Definition for 'Getawaiter'
Mixed Mode Assembly Is Built Against Version 'V1.1.4322'
Parent Control Mouse Enter/Leave Events with Child Controls
How to Read/Stream a File Without Loading the Entire File into Memory
How to Catch All Exceptions/Crashes in a .Net App