I was pointed in the direction of an article on Test-Driven Development on the Code Project by Eli Lopian called Stop Designing for Testability. Eili is one of the team behind TypeMock. The article looks at using Test Doubles and shows an example of using a Fake Object and then using TypeMock, which is a Mock Object library to replace the fake.
The necessity to test doubles comes from the issue that we are trying to write unit tests. But the unit we are placing under test may itself have dependencies on other units. There are a number of issues with testing multiple units.
- When we start writing tests that cover these multiple units we will find that changes can cause mulitple tests to fail, resulting in it being hard to diagnose faults.
- If we cannot seperate out our dependencies we can end up having to write complex test setup code to put a single method under test and may have no easy way to test the success or failure of an operation.
- The dependencies may not be suitable for unit testing, such as components that talk to the database, network, or file system.
It turns out of course that the act of getting our unit under test forces us to decouple it from problematic collaborators by using a test double. This has the virtue Making our classes testable helps move us toward the Open Closed Principle (OCP) and the Dependency Inversion Principle (DIP). This property of Test-Driven Development is sometimes called Emergent Design and is a key benefit of the TDD approach.
Mock object libraries take some of the work out of creating test doubles, they do this by creating an instance using reflection and allowing you to set the return values method calls. Mock libraries can also allow you to confirm that you get the interactions you expect. There is an issue here around maintainability. Fowler has a good summary in Mocks Aren’t Stubs of the issues here. You should be aware that opinion is divided in the TDD community over the dangers and value of mocks as opposed to stubs. My experience here is that interaction based testing (or behaviour driven testing) is more expensive to maintain, because the test peers into the implementation making refactoring of that implementation expensive as it tends tor require changing the test. I went heavily with interaction based on previous project for DB access, where would now use a fake Repository instead. Other people may have different experiences.
TypeMock is interesting because its selling point is that you do not need to design for testability. TypeMock intercepts object construction allowing you to replace instances with mocks ‘on-the-fly’. Eli’s article states that this is a principle advantage of TypeMock, not needing to design for testability. But by removing the need to design for testability TypeMock also risks removing the driver for emergent design. Simply put if I can check the objects that my class is composed from without needing to inject them, I don’t have the motivation from TDD to decouple them and as a result I won’t see OCP or DIP emerging. For this reason I always feel that TypeMock is too sugary. It seems tempting, it tastes good for a bit, but ultimately overconsumption will make you sick. BTW the record and play model of mocking is available in Rhino Mocks, without the same perils.
I tend to see an enthusiasm for TypeMock among people who don’t have a very good grounding in the properties of good OO designs. Often those who think that OO begins and ends with encapsulation.
A number of people raise the issue of the value of using TypeMock with legacy code i.e. code without tests. I’m cautious here but can see the argument in that it may be one way to provide a seam for behaviour preserving tests to use object construction. The danger I think is that you will get addicted to this approach and thus not be motivated to refactor your design. I’m still undecided on this usage of TypeMock, but my gut feeling is that it could be very easy not to break out of the big ball of mud that you probably have if you use TypeMock as a crutch.