If you are interested in mocking a static member or class in order to facilitate testing a component in isolation, you are traveling down the wrong path. First, to be blunt, you cannot mock a static. Static members belong to the AppDomain, and are not replaceable instances. For instance, if I have a class with static methods called SqlHelper (like version 2 of the DAAB), and I want to unit test a class that calls methods on SqlHelper, I’m stuck. I can’t do it. SqlHelper’s static methods call directly into data access code, so now anything that calls SqlHelper has a transitive dependency on the data access code (and most likely the database behind it).
So you have code that can’t be tested in isolation. What do you do?
- Don’t waste you time trying to find a solution to mocking the static members of SqlHelper. You can’t do it. Just like you can’t run Java Swing code inside a WinForms .Net project – there’s no point in searching for a solution because one doesn’t exist).
- Refactor your code because your component is highly coupled. You desire loosely coupled code. Change your SqlHelper class’s static members into instance members, or if you can’t, wrap it in another class – let’s call this SqlRunner.
- Accept an instance of SqlRunner in the constructor of the component you are testing; save it in a class-level variable.
- Unit test to your heart’s content.
It’s really that simple. In your test, you can create a dynamic mock of the SqlRunner class and pass that into the constructor of your tested component. Your component will now call out to your mock, and you have succeeded in testing your component in isolation.
You may be wondering what to do if you need to call some static members in the .Net framework. For instance, what about HttpContext.Current in a web control? Current is a static property that returns the current instance of the HttpContext class. You do not want to call that property directly in your code if you ever hope to test it. In that case, use the same technique as above with a thin wrapper class that knows how to get HttpContext.Current.
If you still aren’t convinced about the rigidity of statics in code, feel free to keep searching, but when you come back around and follow the above steps, come back and leave a comment.
A colleague and I have been talking about Design for testability over the past couple of weeks. The conclusion we came to was that to be able to design for testing, you really need to understand and have good OO knowledge. You need to understand why two objects have high coupling (which normally mean the objects are hard to test) and why cyclomatic complexity is an important metric to keep your code simple.
The following areas need to be addressed to be able to do effective TDD:
OO principles – like always code against interfaces
Refactoring – without this knowledge the TDD mantra is nullified
Design Patterns – to know how to solve those recurring problems
People also needs to understand where and what to test. I’ve found a lot of beginners don’t understand the difference between Unit Test and Functional tests. They write unit test at a functional test level and then don’t understand why the tests are brittle and break constantly.
Ideas like Mocking and stubbing is also important, but they do depend on design for testability. You need to grasp concepts like dependency injection to take full advantage of mocking frameworks.
I’ve posted on how to use TypeMock.NET to replace an external dependency in a SOA type application. You can find the article at the following link:
http://exceptionz.blogspot.com/2006/01/using-typemocknet-to-mock-external.html
cheers,
Maruis Marais
Yes, I have looked at TypeMock, and it’s trying too hard. The solution to mocking a static isn’t to subvert the runtime but to change the static to an object that works _with_ the runtime.
You can make a pig fly by shooting him out of a cannon, but you’ll kill your pig in the process.
Using statics all over the place will kill your software. Perhaps you called my bluff when I said “you cannot mock a static.” Ok, you win. My next question is: Do you really _want_ to mock a static?
Have you takened a look at TypeMock ?