Unit Testing DateTime.Now In C#, Without Using Interfaces
Unit testing is a hugely important part of the software development process, it ensures that individual units of your source code do what they’re meant to do and helps ensure overall software quality. Mocking frameworks are present in most programming languages and exist to make the process of unit testing easier, by mimicking the behaviour of real program objects in a controlled way.
The limitations of mocking frameworks vary, but they’re usually greatly determined by the underlying platform. For example, in dynamic and interpreted languages like Python/Ruby, mocking frameworks tend to be a lot less constrained because the interpreter provides a lot of functionality to modify the runtime state of the program. However, when it comes to strongly typed compiled languages like C#, the story is quite different, mocking frameworks usually have to resort to things like interface inheritance via runtime code generation and as a result are unable to mock certain things like static classes and non-virtual methods.
Pose is a cross platform mocking/isolation framework for .NET that circumvents this constraint by using runtime code generation to rewrite the flow graph and redirect calls to a specified method to user provided delegates. In simpler terms, it lets you replace any .NET method (including static and non-virtual) with a delegate all at runtime.
A very standard scenario where Pose comes in handy is when you’d like to test a piece of code that uses the return value of
DateTime.Now to determine whether to perform some action or not. Consider the following snippet:
public static string Greet()
if (DateTime.Now.Hour < 12)
return "Good morning!";
return "Have a great day!";
The above code is simple enough but hard to unit test considering you have no control over the return value of
DateTime.Now . The typical approach in this case is to create an interface (e.g.
IDateTime) that will have a
Now method, pass that as an argument to the
Greet method and use it in place of
DateTime.Now . With Pose, all you need to do is create a
Shim for the
Now method, like so:
Shim shim = Shim.Replace(() => DateTime.Now).With(() => new DateTime(2004, 4, 4, 11, 50, 0));
The above code simply tells Pose that you’d like all calls to
DateTime.Now to always return
new DateTime(2004, 4, 4, 11, 50, 0) . The final step is simply to surround the call to the
Greet method (or any other methods earlier in the flow graph that calls it) with a
PoseContext accepts a list of shim objects and a delegate containing the block of code you’d like to apply your shims to. Pose goes ahead to execute that block of code immediately and from the above example
DateTime.Now will always return the same value you specified, regardless of the actual time of day.
With Great Power…
There are a lot more things that can be achieved with Pose other than freezing time. Being able to replace a method at runtime opens up endless possibilities, you can even create your own implementation of a filesystem and replace all
System.IO.File.* methods and Pose will automatically redirect calls in your assembly and third party assemblies it references to your implementation.
What other scenarios do you think Pose could come in handy? I’ll love to hear them in the comments!