You’ve probably heard of unit testing. If you are like I was a few years ago, your mouse is hovering over the “close” button right now. But wait! Don’t go away just yet. Over the past few years I have come to realize that unit testing is not only a good idea, it’s essential to developing quality code. I do believe however, that unit testing can be overdone and there is a balance that should be achieved. In general though, unit testing is now an essential part of my development process.

Justification for Unit Testing

Recently when refactoring a large codebase, I was saved by the unit testing framework I had developed months earlier. These changes I made were large and sweeping. They affected almost every area of the codebase, which ended up being thousands of lines. I had earlier developed a comprehensive unit testing framework that thoroughly exercised the code and tested for expected outputs for many different scenarios including edge cases. This framework ended up saving me immeasurable frustration. Had this not been in place, how on earth would I have known if my changes were breaking other functionality? As it stood, I was able to make my changes, ensure it passed all the unit tests, and go to sleep that night confident that I hadn’t broken anything for backwards compatibility.

The case can be made that developing a good unit testing framework just takes too much time and slows down production. While it’s very true that it does slow down production, I have come to realize that it’s a necessary up-front cost to invest in the long-term health of a project. The hours saved down the road will more than make up for the initial investment, not to mention the peace of mind.

When Unit Testing is a Hindrance

Lest I sound like a gushing groupie, I will freely admit that I believe there are times when unit testing can be a hindrance. The main time this comes into play is when expected results are unknown or are fluctuating rapidly during the development process.

In an ideal world we would have a list of requirements that are set in stone, and the deliverable product would be whatever meets those requirements. I remember ACM programming competitions in college. I loved them because you had a discrete set of inputs and a deterministic, predictable output based on those inputs. Your job was to produce the exact output as quickly and efficiently as possible. That would have been a perfect scenario for unit tests (alas, bonus points are not awarded for testing frameworks in the ACM competitions).

Real life is not always ideal. Requirements change. Sometimes, requirements are not always fully fleshed out when development begins. Sometimes, even though requirements may be defined, I have not fully solidified in my mind the best implementation approach. Often, I start coding as a way of fleshing out my ideas. Sometimes this code turns into the production deliverable, and sometimes it’s trashed.

In situations like this where I am developing rapid prototypes, I believe unit testing gets in the way. Why develop tests when I know things are going to change? Wait until the implementation details have solidified before creating a unit testing framework. This will most certainly be well before any code goes into production, but may be a bit down the pipeline of the development process.

I can almost hear the cries of “heresy” as torches are being lit and pitchforks sharpened.

PHPUnit Framework

One thing I greatly admire about the Rails community is their embracing of unit testing. It is built right into the framework and strongly encouraged from day one. Unfortunately, PHP has no such principles. As with most things in PHP, good development practices take self discipline and resolve.

There is however, a fantastic unit testing framework for PHP called PHPUnit. The more I’ve learned about PHPUnit, the more impressed I have become. It really has a full suite of features that make building and maintaining tests a breeze. It has the capability of constructing and destructing test data in a database on the fly, the ability to run a single test with multiple data sets to test edge scenarios, and compiles comprehensive code coverage reports. And that’s just the tip of the iceberg.

Conclusion

It took me a while to come around, but I am fully in agreement with the necessity and utility of unit testing frameworks. Today if I were to release code that was not covered by unit tests, it would feel like standing naked before a crowd. While I’m not 100% in agreement with the mantra of developing tests first, I do always take the time to develop good tests before releasing anything into the wild.