Archive for December, 2007

Unit testing; how far do you push the envelope?

December 4th, 2007 by Oscar Huseyin

Over the years, l’ve read lots of commentary, white papers, best practice papers, books on the topic of TDD. I’ve heard the rant of many TDD evangelists who preach about how total code coverage brings you closer to code quality perfection and how you’ve failed when you’ve not been able to achieve these goals. Sure, this is an extreme example of evangelical preaching, where in actual fact, most of these individuals commonly drum down their hard line views of testing by using words like “pragmatism” and statements like “do what works best”. But, why do l feel as if I’ve failed if l have not got 100% code coverage? It’s because l, to some degree, shared some of the religious views about testing.

I’m now at a point where I’m beginning to rethink some of my beliefs about testing after many years in the trenches. So, l’m at the crossroads settling on a methodology that, l feel, works the best. What level of unit testing is really required to meet the business needs?

I’ll start by analysing two “special interest” projects to see what the outcomes they delivered based on the business expectations.

Firstly, let me talk about a project that was one extreme; no mandated position on unit testing. The project was highly successful, where the business expectations were met and exceeded. Donning my evangelist hat, I’d say the project outcomes were a fluke and it was a miracle that we were able to make any changes to the application without having a negative impact on functionality. Looking back, the project was definitely not a fluke; we made lots of changes to the application without any regressive impact. We knew our issues and had the right processes in place to gate-check the application functionality pre-release. For example, a week before each release, every developer had an area of expertise in the application which they would spend approximately a week testing the functional area and making any spot fixes as need be. We were not very clever about our testing methodology, but we delivered on time, on budget and exceeded customer expectations.

Now, let me tell a story of another, very different project, one that’s in stark contrast to the first one. This application had literally 98% code coverage. Unit tests, integration tests, front end screen tests, water tight code reviews, continuous integration, nightly deploys, every agile practice and quality assurance process under the sun. Did the code meet the business expectations? Well, yes; but it was expensive. It took twice as long to develop an application feature, and we mandated near perfect code coverage. Was this approach more successful than my first example? Not really. Sure, we had more confidence in making changes to the code base and having an “immediate view” of regression impact of the change. But the business paid a price for all of that. A very heavy price. One would think, given the money it cost for development to test the application, that the number of defects would be significantly reduced; but they weren’t. We had lots of functional and non-functional defects detected by testing which was effectively misinterpretation of  business requirements or some gap in the business logic.

Which, from a business perspective, was more successful? Both. The corollary is that a heavily tested application cost lots of money and takes longer to build. This l have seen first hand. So, time to answer the titan question from my own experiences.

As a developer, you need to test the components that you write; theres no arguing that. Otherwise, how else can you prove the functionality of your components? Bu, just how far should we push the envelope?

My view is simple. We all need to be pragmatic about how we approach our unit testing. We should always stop and ask ourselves “are we going to far with our unit testing?”. As a developer, we are faced with this question constantly. We should always do the most to prove our components are functionally correct, but also write the least amount of unit test code to ensure our testing solution remains simple yet effective.  After all, a good developer is a lazy one.