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()
.
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).
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 code dependent on DateTime.Now
Kata
is dependent on an implementation concretion when it should be dependent on an abstraction. That would allow Kata
the flexibility at accept different implementations of the abstraction.
public class Kata {
private readonly IClock clock;
public Kata(IClock clock) {
this.clock = clock;
}
public int GetAgeFromDOB(DateTime birthday) {
var now = clock.Now;
var age = now.Year - birthday.Year;
if (birthday > now.AddYears(-age)) age--;
return age;
}
}
public interface IClock {
DateTime Now { get; }
}
The two implementations of IClock
can be kept simple based on the requirements stated in the question.
The SystemClock class needs to implement a DateTime method that returns DateTime.Now
public class SystemClock : IClock {
public DateTime Now { get { return DateTime.Now; } }
}
The StaticClock method needs to implement a DateTime method that returns a DateTime value that was passed to its constructor.
public class StaticClock : IClock {
public StaticClock(DateTime now) {
this.Now = now;
}
public DateTime Now { get; private set; }
}
Which should allow you to get the desired results.
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 a function containing DateTime( now )
You could instead pass in the $date_start
variable to the function, and when you call it in your test it would be the same every time ie
function testMymethod(){
$date_start = new DateTime('2011-01-01');
$class->getSomeInfo($id, $date_start);
//assertions
}
And your method signiture would change to:
class myclass {
public function getSomeInfo($id, $date_start = new DateTime()){...}
}
How to test code that uses DateTime.now in Flutter?
If you use the clock package for code depending on DateTime.now()
you can easily mock it.
Other than creating a custom wrapper around DateTime.now()
, I don't think there is a better way than what the clock
package provides.
Related Topics
Serialize Class Containing Dictionary Member
How to Deserialize Xml to Object
Get a Screenshot of a Specific Application
Can't Get Czech Characters While Generating a PDF
Accessing a Variable from Another Script C#
#If Debug VS. Conditional("Debug")
How to Create a .Net Datetime from Iso 8601 Format
Cast List<T> to List<Interface>
Why Do Assignment Statements Return a Value
How to Bind a List to a Combobox
How to Deal with Files with a Name Longer Than 259 Characters
How to Read a File Even When Getting an "In Use by Another Process" Exception
Find Number of Decimal Places in Decimal Value Regardless of Culture
How to Read an Attribute on a Class at Runtime