Recently, i’ve been looking more into TDD and mocking in particular.
I’m well versed with TDD and unit testing in general, and although i’ve dabbled in mocking before with NMock, i never really pursued it deeper; probably based on the combination of a number factors:
- The product i was working on had it’s own in-house, custom-built ORM/OPF which wasn’t interface driven
- There were patterns for testing code based on the aforementioned OPF which didn’t lend themselves for mocking too easily
Either way, i’ve sunk my teeth deep into it, and one thing that irked me about mocking was why I always seem to be mocking interface implementations and not concrete classes. From my (limited) understanding of how mocking frameworks work, one would assume that the definition of an object exposed through public methods on a concrete type would still allow you to mock the object. In a nutshell, i was wondering why can’t i mock my concrete classes?
Lets use an example (apologies if there are compile errors – i’m doing this off the top of my head)….I’m writing a class to perform calculations (uninspiringly named “Calculator”). I realise it’s a trivial example, so lets make it interesting by saying that the actual calculation logic won’t be handled by my application – it will be handled by a 3rd party object called SuperCalculator which takes the calculation and runs it across an array of supercomputers. As developers, we don’t care about the implementation of the SuperCalculator, only its interface.
So my code would look something like this:
[HTML1]
Now to test this using standard mocking techniques, I would need to pray that there is an interface for the SuperCalculator type
[HTML2]
…and the concrete class would be updated to use the interface definition (note the use of setter injection for mocking – i could have just as easily used constructor injection…)
[HTML3]
…and then your unit test starts making a mockery based on the interface (Rhino mocks and .NET 1.1 used here, but using generic params is just as cool)….
[HTML4]
phew…lot of code, but we got there. Now getting back to what irks me. The fact that we had to PRAY for an interface ISuperCalculator ortherwise we couldn’t mock out the dependency. And when you’re at the hands of a 3rd party library, who knows what you’re going to get.
So my questions came to – “is it possible to mock based on the concrete class?”….a bit of light Googling indicates it is possible, but only if you create a superclass of your concrete implementation and override all “public” methods which would now mean that they all have to be virtual by default, otherwise your test will end up calling code with undesirable results.
Why can’t the mocking framework take a concrete implementation, and mock it based on its public interface? The framework knows the interface to the object via reflection (and with VS2008, the intellisense is damn intelligent by allowing you to extend it), so why can’t it Reflection.Emit() all the necessary members (public/protected) and you can avoid the pain of hoping for an interface for a class that’s out of your control?
The other approach to it is to use a service proxy, and proxy all of the calls to SuperComputer through your OWN class MySuperComputer, which requires you to hand code the interface to SuperComputer, expose an IMySuperComputer, and then mock that….You’re hardly achieving anything though, because you’re just pushing the untestable dependency further down.
ramble ramble….if anyone has a thought on the matter, i’d like to hear it. I’m keen on continuing to use mocks, and certainly believe that implementing interfaces is good practice, but when the code you’re trying to mock is out of your control, what do you do?
[UPDATE]
hmm….after looking at this article it seems to explain one reason why you can’t create a pure mock from a concrete class…
Quote:
Dynamic mock object tools like NMock or Rhino Mocks can only override virtual methods. This might not be so much a problem in other languages, but with the .Net languages all methods are non-virtual by default. This means that some of the behavior that you were trying to remove from the test with a mock is still there. The dynamic mock libraries work by using Reflection.Emit to create a dynamic proxy on the fly for the requested interface or abstract class.
bugger