Abstract current time using function in C#
I've seen many ways to deal with date and time. Hiding it behind an interface, a static class with a single property, ambient context, you name it. I never liked any of them.
Then the enlightenment came. In one of the projects, I've seen a function used to get the current time.
I've never thought of that! It doesn't need much code to put into use and is simple to test.
Take a look at an example.
First, you create a function for getting the current time and then pass it to the DateRangeCalculator.
public void ConfigureServices(IServiceCollection services)
{
Func<DateTime> getCurrentTime = () => DateTime.Now;
services.AddSingleton(_ => new DateRangeCalculator(getCurrentTime));
}
Our calculator implementation can look like this:
public class DateRangeCalculator {
readonly Func<DateTime> _getCurrentTime;
public DateRangeCalculator(Func<DateTime> getCurrentTime) =>
_getCurrentTime = getCurrentTime;
public DateTime GetLastMonth()
{
var currentTime = _getCurrentTime();
var previousMonth = currentTime.Date.AddMonths(-1);
return previousMonth;
}
}
If you prefer a more functional approach, change GetLastMonth method to static and drop the constructor. I will leave it to you as an exercise.
How to test a class with such dependency?
Just replace the implementation in the test like so:
[Fact]
public void PreviousMonthRangeCalculator()
{
Func<DateTime> currentTime = () => new DateTime(2021, 1,1);
var result = DateRangeCalculator.GetLastMonth(currentTime);
result.Month.Should().Be(12);
}
I like this idea because it doesn't require an interface with one method.
When it comes to tests, there is no need to create a mock class.
Less boilerplate, more readable code, what more do you need?