Abstract DateTime access with dependency injection

Why you should abstract your access to DateTime

A simple way to make tests deterministic in regard to date access

João Nadais
Geek Culture

--

Photo by Aron Visuals on Unsplash

Hello everyone!

The concept of dependency inversion is a widely known one, stating that one should depend on an interface rather than on a specific implementation, as it allows our tests to be more deterministic and easier to maintain. However, in the case of dates and times, it is very easy to overlook as they are simple values with no complex logic.

Example code

Let's look at this function as an example

As you can see, the code is fairly simple. It would return the correct greeting based on the current time of the day.

Now let's try to test this code and run those tests:

After running it, this is the result we get:

Since I am running these tests in the afternoon, only the test related to good afternoon will pass. This results in our tests being dependent on whatever time they are being run, making them not deterministic

Solution

One solution to this is abstract the access to DateTime into an interface. Below is an example of this interface:

You can then pass this provider through dependency injection into your class

And the tests would now look like this:

As you can see, now each test is able to pass a specific time of the day. Now, even if I am still running these tests in the afternoon, I get the following result:

This ensures that no matter when you run the tests, the results will be always the same, and you will have no issue with different times of running results in different test execution results

Conclusion

In this article, I wanted to show a common pitfall that I have seen across many codebases in the past, and why a simple solution like this one can not only ensure your tests are deterministic, but also you have a point of reference across your code to where Dates and times are being used

The full repository code can be found here

Even though the snippets of code are in C#, the concepts shown here would be very much applicable in any other language. The difference would be in the libraries used and how the interface would be injected

Hope you liked it and see you at the next one!

--

--