In my previous post, I talked about a technique that I saw for testing time and also about how I simply injected some kind of ISystemTime/IClock interface. The problem with that was having to do injection at every level—including domain entities.
Oren Eini's method, while probably the most simple and easiest to implement (both of which are *good things*) has two small issues:
- Implicit disposability. You have to remember to reset the static lambda expression every time it's set.
- Thread isolation: All calls are to a single, static instance and return the same value—running unit tests in parallel can be dangerous.
With that I mind I decided to create my own small library to address those issues.
Oh No! Another Library
In the past I would normally have put this new code into a library with other infrastructure code. I purposefully avoided mixing this code with any other concern because I want to have a truly static library—one that I compile and continue to use for the next five years without updating it. I want a library that any and all projects can depend upon and has a stable implementation and can be considered as fundamental as Microsoft's BCL (System.*) implementations.
Therefore, I present OpenXtensions.SystemTime. I named it that facilitate Google-fo. OpenXtensions.* will be a set of small libraries related to simple, helper methods and behavior surrounding deficiencies and rough spots in the BCL. Common usage looks like the following:
var instant = DateTime.Parse('"2000-01-01");
using (SystemTime.Is(instant))
{
// do some work
var currentTime = SystemTime.UtcNow;
}
The library is about 7K and is signed with a strong key. It is under the MIT license so you're free to do whatever you'd like with it.
Dependency Injection
For those of you who want to continue to use dependency injection, I created an interface ISystemTime as well as a class SystemTimeAdapter (which implements ISystemTime). You can inject this into your objects as necessary and it will call SystemTime.UtcNow on your behalf.
UPDATE: Davy Brion linked to my previous article on this subject. In the comments for Davy's post, Mel Grubb linked to his solution, which is very similar to the one I have detailed here. For what it's worth, one key different would be that Mel stores a "DateTimeContext" on the thread while I'm storing the DateTime.