As developers we routinely work with code that is not our own, commonly in the form of third party APIs and application frameworks. This post discusses the scenario that almost every developer is likely to encounter at some stage in their career, namely what to do when you have to work with an API or framework dependency that makes unit testing seem impossible.
Faced with the prospect of developing code against a framework that doesn’t easily lend itself to unit testing you generally have a number of options.
The first and obvious choice for some is to abandon the idea of unit testing for part or all of the code that you have written. The reasoning here is, why the hell should I bother to test my code if the framework code lacks the same rigour. After all it’s not your fault, you can always blame the framework developers for painting you into this corner. This attitude is not exactly going to guarantee you a place amongst the great and good of Software Craftsmanship. The facts are that you, as a software professional, are responsible for verifying the code that you write. It is you who will ultimately have to support the code you write when it gets to production, giving you a great motivation to ensure that it functions correctly.
You may have accepted the idea that you need to test your code and decide to go for an off the shelf solution to the problem. There are several unit testing tools available commercially that crack open difficult to test code, enabling you to shine the light of unit testing into the dark and difficult to reach areas of even the most belligerent APIs. Tools like JustMock and TypeMock Isolator allow developers to perform mocking of non-virtual methods, non-public members, sealed classes and static methods and classes making it possible to isolate the code being tested. Sold on this approach? Then it’s time to convince the boss that they will need to plunder the software budget and buy one of these commercial tools. The tools mentioned offer excellent value for money but for the levels of functionality that make them really useful their price may be an issue for some.
Whilst in many respects the commercial mocking tools offer an easy way out of a difficult situation there are reasons to think about what they are doing for you. These tools allow you to create test doubles for types that you either don’t own or are unable to change. If you find yourself reaching out for such an approach take a moment to think about whether you are looking at code that contains a Dependency Inversion Principle violation. Derek Greer writes about this scenario in his post TDD Best Practices: Don’t Mock Others.
One final thought on the commercial mocking tool option, consider what the impact will be on your code if you fail to tackle the root cause of the test problem. In essence you are embarking on a route where you are paying for a tool so that you can preserve a tight coupling between your precious production code and a software dependency that you recognise as having some shortcomings.
Perhaps it is time to consider the last of the options. Time to dig deep and resolve to find a way to test just the code which you have created. This will be an exercise in isolating your code from the framework and platform that it runs on. In embarking on this path you are choosing to refactor your code and tease apart dependencies to the point where you can adequately verify the functionality of your code without the need to stunt drive the software dependency. Along the way you may very well fall out of love with those that wrote the difficult to test API / framework. Don’t be too hard on those that wrote code that you now rely on. Software development has evolved rapidly and testing practices that are widely accepted today were uncommon even a few years ago. Most importantly performing the refactoring process will teach you a great deal about how to write APIs that adhere to SOLID principles, knowledge that you can employ whenever you write code. I’d also argue that if you properly invert your dependencies and refactor your code accordingly you will end up with better production code, I certainly did.