I'm a big fan of TDD and unit testing in general, but there are some things that come with it that can often make life difficult. A tightly coupled applicaiton can be increadibly difficult to unit test. If you implement a logger that uses the enterprise library and you don't want to spawn up the entire library so that you can do a simple test you're going ot have a little bit of difficulty. In fact if you use any static methods that tightly couple tools to the rest of your code then you're going to find unit testing your kind of like trying to chew through your own neck. (makes a funny image doesn't it?)
In our new applicaiton we want implementation to be simple. Static methods are often useful when you have stateless code (like our logger) and the implementation is easy (Logger.Log("message");) but testing is disasterously hard. To get around this we are implementing the Method Object pattern.
I love patterns, when making design decisions it's nice to say: "We've followed this pattern, and this pattern and this design framework" and know that someone before you has at least thought of it enough to put it down on paper, but don't get bogged down. Just because it's a pattern doesn't mean it's good.
At least in this case, I think it is. The Method Object pattern is almost common sense. When I say "I want to use TDD with static methods" after I sift out the abusive comments and weed out the "
You're doing it wrong!" idealists I'm left with some good advice. A singleton is one option, programming to an interface and defining an object is another, a service provider is also a good idea. The best one I've come across is the Method Object pattern.
See this code:
public class Logger
{
public static void Info(string message)
{
// Implementation specific code
}
}
This code is almost impossible to test. It is tightly coupling the application with the logging framework I choose to implement. Method Object will specify that my static class is an API shell calling an instance of an object, which now becomes a static object singleton.
My code becomes:
public interface ILogger
{
void Info(string message);
void Debug(string message);
}
public class EntLibLogger : ILogger
{
public void Info(string message)
{
// Implementation specific code
}
}
public class Logger
{
private static ILogger _Logger = new EntLibLogger();
public static void OverrideInstance(ILogger logger)
{
_Logger = logger;
}
}
And all of a sudden I can mock out my Logging framework using Rhino Mocks (or whatever mocking framework takes your fancy) and still use static methods in my code with loose coupling.
Here is my test code. I'm testing a class with a method called Remove that takes a string. It logs some info and I don't want it to fail because the enterprise library isn't instanciated. I'm using Rhino Mocks to create a mock object of the interface and the OverrideInstance method to setup my mocked logger as the current logger.
public void RemoveTest()
{
MockRepository mocks = new MockRepository();
ILogger logger = mocks.CreateMock();
Logger.OverrideInstance(logger);
Stock target = new Stock();
string remove = "id";
target.Remove(remove);
}
So there you go. I think this is a good method for testing static functions if you feel they would be helpful to your applicaiton.
2 comments:
Could you post the full code?
I know it's been a little while since you posted this...
But thanks, it helped! :)
Post a Comment