In this post I will demonstrate how you can stub the DateTime struct in your unit tests. Most commonly the method DateTime.Now
or DateTime.UtcNow
are used to get the current date and time. Sometimes you make a decision in your code depending on this, which means you want to control this for your tests so you can get better test coverage. You may have some code somewhat like the following in your code base (this is an example from my daily routine):
public class Decision
{
public string WhatToDo()
{
var currentDateTime = DateTime.Now; //The important part
if (currentDateTime.Hour > 8 && currentDateTime.Hour < 22)
return Blog();
else
return Sleep();
}
private string Blog()
{
return "Blog!";
}
private string Sleep()
{
return "Sleep!";
}
}
In the above the current time decides what to do, between 8 and 22 it is blogging time and outside that it is sleep time. If I want to test what happens in the Sleep()
and Blog()
method I have to control DateTime.Now
to end up on that code path, here I will show some approaches on how to do that. The approaches are:
- Constructor dependency injection
- Using a mocking framework
- Injection through inheritance
- Using a Func
- Using a static DateTime
My examples are also applicable to DateTimeOffset. The examples are in C# and I use xUnit for my tests.
Method 1: Constructor dependency injection - the Wrapper class
This is a very common and simple pattern used to control the DateTime.Now
struct or any other type that you need to stub. It is often done by wrapping the DateTime
in a class like below. First we wrap the DateTime
, so that we can provide our own DateTime
value or as a default use DateTime.Now
in the flow outside our tests:
public class DateTimeWrapper
{
private DateTime? _dateTime;
public DateTimeWrapper()
{
_dateTime = null;
}
public DateTimeWrapper(DateTime fixedDateTime)
{
_dateTime = fixedDateTime;
}
public DateTime Now { get { return _dateTime ?? DateTime.Now; } }
}
We then inject the DateTimeWrapper
into the constructor of the Decision
class and use that for getting the DateTime
:
public class Decision
{
private readonly DateTimeWrapper _dateTimeWrapper;
public Decision(DateTimeWrapper dateTimeWrapper)
{
_dateTimeWrapper = dateTimeWrapper;
}
public string WhatToDo()
{
var currentDateTime = _dateTimeWrapper.Now;
if (currentDateTime.Hour > 8 && currentDateTime.Hour < 22)
return Blog();
else
return Sleep();
}
private string Blog()
{
return "Blog!";
}
private string Sleep()
{
return "Sleep!";
}
}
Our old flow is unbroken as it still just gets a DateTime.Now
in the end, but using the above we can now create unit tests where we choose the value used for the DateTime
:
[Fact]
public void ShouldBeBlogWhenHourIsTen()
{
var dateTimeWrapper = new DateTimeWrapper(new DateTime(2020, 01, 01, 10, 00, 00));
var decision = new Decision(dateTimeWrapper);
var whatToDo = decision.WhatToDo();
Assert.Equal("Blog!", whatToDo);
}
[Fact]
public void ShouldBeSleepWhenHourIsTwentyThree()
{
var dateTimeWrapper = new DateTimeWrapper(new DateTime(2020, 01, 01, 23, 00, 00));
var decision = new Decision(dateTimeWrapper);
var whatToDo = decision.WhatToDo();
Assert.Equal("Sleep!", whatToDo);
}
Above we instantiate the DateTimeWrapper
and provide it with a DateTime
used for testing. The first test shows that at the time 10 we get the value "Blog!"
. The second test shows that at the time 23 we get the value "Sleep!"
.
This approach for controlling the DateTime.Now
value is quite verbose, but it has its advantages. It is simple and uses just what is within the framework as no dependencies are required, it is also well known and used.
Method 2: Using a mocking framework
If you write a lot of unit tests you are likely using a mocking framework. In this example I use Nsubstitute to mock an interface that has the responsibility for fetching the current DateTime
. It is much like the previous example but less verbose and leverages your mocking framework. First we create an interface and an implementation of it:
public interface IDateTimeWrapper
{
public DateTime Now { get { return DateTime.Now; } }
}
public class DateTimeWrapper : IDateTimeWrapper {}
In the above we create a simple interface with a "Now" method that returns DateTime.Now
. This we need to use for our Decision class and is injected into the constructor:
public class Decision
{
private readonly IDateTimeWrapper _dateTimeWrapper;
public Decision(IDateTimeWrapper dateTimeWrapper)
{
_dateTimeWrapper = dateTimeWrapper;
}
public string WhatToDo()
{
var currentDateTime = _dateTimeWrapper.Now;
if (currentDateTime.Hour > 8 && currentDateTime.Hour < 22)
return Blog();
else
return Sleep();
}
private string Blog()
{
return "Blog!";
}
private string Sleep()
{
return "Sleep!";
}
}
Through our IDateTimerWrapper
we are now able to control what DateTime
is returned when the Now method is called. We can now substitute what is returned by creating a mock (substitute in NSubstitute) that returns the DateTime
we want. We repeat the previous tests using mocking instead:
[Fact]
public void ShouldBeBlogWhenHourIsTen()
{
var dateTimeWrapper = Substitute.For<IDateTimeWrapper>();
dateTimeWrapper.Now.Returns(new DateTime(2020, 01, 01, 10, 00, 00));
var decision = new Decision(dateTimeWrapper);
var whatToDo = decision.WhatToDo();
Assert.Equal("Blog!", whatToDo);
}
[Fact]
public void ShouldBeSleepWhenHourIsTwentyThree()
{
var dateTimeWrapper = Substitute.For<IDateTimeWrapper>();
dateTimeWrapper.Now.Returns(new DateTime(2020, 01, 01, 23, 00, 00));
var decision = new Decision(dateTimeWrapper);
var whatToDo = decision.WhatToDo();
Assert.Equal("Sleep!", whatToDo);
}
You may find this method to be more elegant than the previous, but it does require for you to use a mocking framework. It also uses fewer lines of code for the wrapper. This is the most common way to control DateTime
that I encounter.
Method 3: Injection through inheritance
I got this idea from an answer on this question on stackoverflow, I had never seen or thought about using this approach before.
We start by defining our Decision class again, this time we add the keyword virtual to a GetDateTime()
method which returns DateTime.Now
. This makes it possible to override this method if we inherit from our Decision class, which we will use to control what GetDateTime()
returns:
public class Decision
{
public string WhatToDo()
{
var currentDateTime = GetDateTime();
if (currentDateTime.Hour > 8 && currentDateTime.Hour < 22)
return Blog();
else
return Sleep();
}
protected virtual DateTime GetDateTime()
{
return DateTime.Now;
}
private string Blog()
{
return "Blog!";
}
private string Sleep()
{
return "Sleep!";
}
}
In order to test with another DateTime
, we need to create a stub (a "test double") as seen below:
public class DecisionTestStub : Decision
{
private readonly DateTime _dateTime;
public DecisionTestStub(DateTime dateTime)
{
_dateTime = dateTime;
}
protected override DateTime GetDateTime()
{
return _dateTime;
}
}
This lets us override what GetDateTime()
returns but leaves everything within the class as is, this enables us to have control over the DateTime
which can be used for testing purposes. This is demonstrated below where we use our stub with specific DateTime
values:
[Fact]
public void ShouldBeBlogWhenHourIsTen()
{
var decision = new DecisionTestStub(new DateTime(2020, 01, 01, 10, 00, 00));
var whatToDo = decision.WhatToDo();
Assert.Equal("Blog!", whatToDo);
}
[Fact]
public void ShouldBeSleepWhenHourIsTwentyThree()
{
var decision = new DecisionTestStub(new DateTime(2020, 01, 01, 23, 00, 00));
var whatToDo = decision.WhatToDo();
Assert.Equal("Sleep!", whatToDo);
}
This approach has some advantages to it: It is not intrusive to the Decision class as it only requires us to use the keyword protected and move how we get our DateTime
into another method. There is no need to inject anything into the constructor, so seen from the outside it is untouched. Our stub carries all of the code needed to change the DateTime
(the injection in the constructor) for each test. The only disadvantage I can think of, is that we actually do not test our Decision
class directly, but an inheritance of it.
Method 4: Using a Func
You can also pass a Func to your constructor or method that will return a DateTime
. You can make it have the default value null
and if so use DateTime.Now
, so you do not interfere with the signature or method or constructor. Below I have added this to the WhatToDo
method:
public class Decision
{
public string WhatToDo(Func<DateTime> getCurrentDateTime = null)
{
var currentDateTime = getCurrentDateTime == null ? DateTime.Now : getCurrentDateTime();
if (currentDateTime.Hour > 8 && currentDateTime.Hour < 22)
return Blog();
else
return Sleep();
}
private string Blog()
{
return "Blog!";
}
private string Sleep()
{
return "Sleep!";
}
}
As mentioned, we use the DateTime
provided by the Func
, and if the Func
is null
we use DateTime.Now
instead. Below we repeat the same tests as earlier:
[Fact]
public void ShouldBeBlogWhenHourIsTen()
{
var decision = new Decision();
var whatToDo = decision.WhatToDo(() => new DateTime(2020, 01, 01, 10, 00, 00));
Assert.Equal("Blog!", whatToDo);
}
[Fact]
public void ShouldBeSleepWhenHourIsTwentyThree()
{
var decision = new Decision();
var whatToDo = decision.WhatToDo(() => new DateTime(2020, 01, 01, 23, 00, 00));
Assert.Equal("Sleep!", whatToDo);
}
This is quite simple and there is no need for stubs, mocks or anything else. As mentioned the above can be repeated having the constructor take the Func<DateTime>
instead of the method.
Method 5: Using a static DateTime
I believe I should mention this approach, but mostly as a warning against it. Even though it is arguably a simple way to achieve this, it also has a major pitfall, you cannot run your tests in parallel. Since this approach relies on a static variable you will run into problems with concurrent calls to it. You could implement some sort of lock but again your tests will block each other and not run in parallel. This reduces performance of your tests, you may see this as less important if your tests run fast.
We first create our DateTimeWrapper
class with a static Now
property that returns a preset DateTime
or DateTime.Now
if the preset DateTime
is not set (null). We use the method Set()
to set the value for the DateTime
and Reset()
to set it to null. You can see the implementation below:
public class DateTimeWrapper{
private static DateTime? dateTime;
public static DateTime Now { get { return dateTime ?? DateTime.Now; } }
public static void Set(DateTime setDateTime)
{
dateTime = setDateTime;
}
public static void Reset()
{
dateTime = null;
}
}
Next we use our DateTimeWrapper.Now
method in our Decision
class in order to get a DateTime
:
public class Decision
{
public string WhatToDo()
{
var currentDateTime = DateTimeWrapper.Now;
if (currentDateTime.Hour > 8 && currentDateTime.Hour < 22)
return Blog();
else
return Sleep();
}
private string Blog()
{
return "Blog!";
}
private string Sleep()
{
return "Sleep!";
}
}
Just as all the previous examples we now start using our new approach on our two test cases:
[Fact]
public void ShouldBeBlogWhenHourIsTen()
{
var decision = new Decision();
DateTimeWrapper.Set(new DateTime(2020, 01, 01, 10, 00, 00));
var whatToDo = decision.WhatToDo();
Assert.Equal("Blog!", whatToDo);
}
[Fact]
public void ShouldBeSleepWhenHourIsTwentyThree()
{
var decision = new Decision();
DateTimeWrapper.Set(new DateTime(2020, 01, 01, 23, 00, 00));
var whatToDo = decision.WhatToDo();
Assert.Equal("Sleep!", whatToDo);
}
In the above we set the DateTime
we wish to test again on our DateTimeWrapper
, which our Decision
class then gets using the Now
method. This way we can control the DateTime
that our Decision
class uses.
We use the reset method in our teardown or setup method in our tests. For xUnit that is the constructor of our tests, therefore I have added it here:
public UnitTest() {
DateTimeWrapper.Reset();
}
If you forget this other tests that rely on DateTime
may fail as they get the DateTime
from the last run test. This is also why we cannot run tests in parallel.
The biggest advantage of this approach is that it is simple, but you cannot run your tests in parallel, which is a "no go" for most.
That is it
These were my approaches and examples on how you can test code that is depending on the DateTime
struct. If you know a smarter or easier way please let me know in the comments down below, I would love to add that to my list. Any other comments are of course also appreciated as well.
If you wish to read some great resources on Test driven development, test doubles or dependency inject, please see the following resources:
Disclosure: Bear in mind that the following links in this post are affiliate links and if you go through them to make a purchase I will earn a commission. Keep in mind that I link these companies and their products because of their quality. The decision is yours, and whether or not you decide to buy something is completely up to you.