Better Testability With Static Classes
If you’ve been following me, you know by now that recently I’ve been dedicating my extra time enhancing ServiceInsight application. For those of you living under a rock, it is a part of NServiceBus suite of applications and the focus there is to give you a better tooling so that you’ll have a much better experience using NServiceBus framework. Among the few tools we are building are ServicePulse which is designed for DevOps and ServiceInsight which is targeted mostly for average Joe developers. Now these two tools should be able to interact with each other so that when you see there’s an error message in ServicePulse, you can open that message in ServiceInsight and see more developer friendly information regarding that error to find out what has caused it. You can read more about the implementation of this feature here, but here I’m talking about an issue I had creating and testing it, which hopefully is helpful to someone as well.
When building the invocation of ServiceInsight, I needed to read passed in parameters through the command line. So everyone with a bit of .NET knowledge knows that you can get the arguments like this:
public class Program
There’s another way of accessing passed in command line arguments, which is probably useful if you’re creating a WPF application or need to access to command line arguments later and not as soon as the app launches. You can access them through System.Environment object and it looks like this:
public class App : Application
Now how would you test this? I’m aware of all the good Command Line parsing libraries out there, but it’d be an overkill, but you still need to parse the argument, and that’s going to need some unit testing. To make the story short, I came up with a parser and wrap that on an interface, so I had something like this:
public class CommandLineArgParser : ICommandLineArgParser
Now how would you test this thing? Because of the fact that it is using a static object (here System.Environment) and particularly it is a System object, you can’t just mock that, so how would you write any unit tests to ensure your parsing is doing what you intended?
First obvious way is to create an interface and a wrapper around the Environment object and then use the interface. That comes with the burden of creating the wrapper, which depending on the situation, is a lot of unnecessary code to write. But is there anther more generic solution? Turns out, there is one!
How about creating an interface, then on runtime, creating something similar to the wrapper: a class that would implement the interface and then delegate all the calls to the static class? Here’s how you can do it using a Autofac Module:
public interface IEnvironment
The magic is in the CallForwarderInterceptor, which is a DynamicProxy interceptor. What it does is that it generates a proxy to the interface and when you make a method call at runtime on the proxy object (the interface), it looks for a method with exact matching arguments and output and then it’d call that method, get the result and return it as a part of the original method call. Pretty neat, if you ask me. The implementation posted here, works with either generic or non-generic classes alike and is not limited only to static classes.