Bending DateTime in .NET for Improved Code Testing
Written on
Chapter 1: Introduction to DateTime Mocking
Mocking DateTime in .NET can be quite challenging. However, there's a more efficient way to manage it.
As a seasoned engineer, I've faced the issue of having to deal with DateTime.Now or DateTime.UtcNow in my code. When I write tests, validating the exact time can be problematic due to the milliseconds that elapse between executing the code and performing the check. While this may seem trivial, it can be quite bothersome, especially since I prefer to ensure the accuracy of every aspect of my code.
Fortunately, there's a straightforward solution to this dilemma. Before diving into the details, I want to extend my gratitude to Andrew Harcourt, Andrew Wickens, and Jared Wilton for their invaluable encouragement.
To summarize, you can utilize my SimpleDateTimeProvider NuGet package to effectively address this issue. Below, you'll find the implementation details.
The Solution
I've developed a DateTimeProvider that consists of an interface along with two distinct implementations. One implementation returns the actual system values, while the other provides mocked values that users can set as needed.
Interface Definition
public interface IDateTimeProvider
{
DateTime Now { get; }
DateTime Today { get; }
DateTime UtcNow { get; }
}
System Implementation
public class SystemDateTimeProvider : IDateTimeProvider
{
public DateTime Now => DateTime.Now;
public DateTime Today => DateTime.Today;
public DateTime UtcNow => DateTime.UtcNow;
}
Mock Implementation
public class MockDateTimeProvider : IDateTimeProvider
{
public DateTime Now
{
get => this.now.ThrowIfNotSet(DateTimeType.Now);
set => this.now = value;
}
public DateTime Today
{
get => this.today.ThrowIfNotSet(DateTimeType.Today);
set => this.today = value;
}
public DateTime UtcNow
{
get => this.utcNow.ThrowIfNotSet(DateTimeType.UtcNow);
set => this.utcNow = value;
}
}
Using the DateTime Providers
This approach is straightforward. You can easily implement the system provider under the IDateTimeProvider interface in your functional code. If you're familiar with dependency injection libraries, you’ll find the syntax intuitive—just follow the established pattern.
builder.Services.AddSingleton<IDateTimeProvider, SystemDateTimeProvider>();
Next, create your service class and employ the registered SystemDateTimeProvider through the IDateTimeProvider interface. You can then use the provider to set DateTime values within your class.
public class Service
{
private readonly IDateTimeProvider dateTimeProvider;
public Service(IDateTimeProvider dateTimeProvider)
{
this.dateTimeProvider = dateTimeProvider;}
public string DateTimeNow()
{
return $"DateTime.Now is {this.dateTimeProvider.Now}";}
}
The core objective of this implementation is to facilitate testable code. Now, with the class defined above, you can substitute in the MockDateTimeProvider for testing purposes, allowing for controlled DateTime values.
Testing Example
The following example illustrates how to create a test using XUnit, along with Shouldly for assertions.
[Fact]
public void Today_ShouldReturn_MockedToday()
{
// Arrange
var provider = new MockDateTimeProvider();
var service = new Service(provider);
var today = DateTime.Today;
provider.Today = today;
// Act
var result = service.DateTimeToday();
// Assert
_ = result.ShouldBeOfType<string>();
result.ShouldBe($"DateTime.Today is {today}");
}
Where to Find This
All of this is open-sourced. You can explore my work on GitHub at the SimpleDateTimeProvider repository and find the NuGet package there as well.
Connect and Support
If you find this information helpful or want to check out my other projects, please connect with me on LinkedIn or GitHub. Your support is always appreciated, and I welcome any contributions, even if it’s just $1 on GitHub Sponsors or Buy Me a Coffee.
Chapter 2: Enhanced DateTime Handling
In this video, titled "The RIGHT way to deal with Date and Time in C#," you'll discover best practices for managing DateTime in C# applications.
Additionally, check out the video "C# Tutorial - How to create line chart | FoxLearn," which provides insights on implementing line charts in your applications.