My Unit Testing Path

I remember being shown a scary looking v-shaped diagram in my early days at Andersen Consulting.  I was an analyst and was off in the wilds of western Illinois with a slew of other brand new analysts all learning the Andersen Consulting way of building software.  I recall working in teams of three using os-warp and a RAD UI development tool whose name I didn’t know then and still do not know.  In any case, the v-shaped diagram was an overview of how software was to be built.  Starting from the left one went down the v passing through requirements gathering, functional design, technical design until finally reaching the v-bottom, implement.  The first step back up the other side of the v, was unit testing.  There it was, I didn’t know really what it meant beyond do something to make sure things you just developed at the bottom of the v work!

The v-shape diagram was Andersen’s waterfall methodology.  We actually used some variant of it on the projects I worked on, and sure enough unit testing needed addressing.   It was a box on a project plan, but usually it was achieved through manual UI testing.  At the time and for several years to follow  unit testing actual code was achieved very informally at best.  I rarely wrote test harnesses to actually exercise routines that had no UI.  If something wasn’t working chances were I’d find some place in a UI that I could use to call my code and have my friendly debugger ready to stop and see what was going wrong.  Certainly not a convenient way to test.  I suppose we worked from the assumption we didn’t create a lot of bugs so why go through too much effort to find them, especially before they proved themselves to exist!  Certainly this was an optimistic ideology, if not a correct one.  Looking back I am amazed how little anyone was concerned with unit testing.  Whether it was my fellow developers or our managers, there was almost never a gatekeeper asking us to show proof that our work was tested.  Most of our bug fixing was driven by large system testing efforts, so bugs were hard to isolate and fix.

It was a few years later working with a small consulting firm I ran across a java developer using a tool that had all these red and green lights.  When I inquired as to what this tool was he responded ‘jUnit’.  I asked what it was for and received my first lesson regarding test driven development, and more importantly, automated unit testing.  When I realized there was an ‘nUnit’ off I went to get it and use it myself.  This seemed like the perfect way to handle unit testing,  no more finagling ways to isolate my code in the debugger when something wasn’t working right.  This was going to make my life so much simpler!   What became apparent as I tried to use nUnit is that I needed more than a automated testing tool to effectively unit test my code, I had to write code that was actually testable.  This was probably the biggest epiphany of that experience.  I wasn’t sufficiently unit testing because I wasn’t writing code that could be easily tested.  When something is hard to do, you don’t do it often.

It was at that point that I started altering my coding practices to create more testable code.  Quickly I ran into the concept of using mock objects as a way of allowing the isolation of routine for unit testing.  It was much easier to call ‘Save’ on a mock object when running  a test over and over, then to actually save data to a file or database and then have to reset the data.  The interesting issue became how to code so that you could replace the real object with a mock object when running a test.  I favored an overloaded constructor, but some I’ve seen use factories or providers they can set to return a mock instead of a real object.  I’m sure there are other methods too.

Working on many legacy code bases I still haven’t adopted a test driven approach, but I have tried to work unit tests into the legacy code bases I encounter and  refactor them to be more testable.  The questions I struggle with today usually surround issues of what should a test do? how many tests should I have for any one method?  should I have a separate test class for each method or one per class?  What’s been interesting is as I have worked to understand how to better unit test my code, this has led to a far more thorough understanding and awareness to the code’s architecture.  You can’t test what you can’t isolate.  It is also difficult to test routines that have poor cohesion or tight coupling.  To this end trying to more testable has led me to create more cohesive and less coupled software.

There is no more sure way of knowing something works then by proving it.  At this point I believe all code should be built with accompanying unit tests.  Whether the unit tests are created first is another matter.  I may take another crack at actually TDD, but at this point I’m not really following it.  I have run across too many who have an almost religious devotion to TDD.  If there is anything I’ve learned over the years it’s that smart people can achieve success through many different methods.  I tend to be suspicious of anyone who tells me they know the only right way something should be done.

I’m lucky enough today to be working with a group who are highly quality conscious.  We are pushed to put meaningful unit testing in place, and through doing this have also created better architecture in our work.  We also get to work through the issues of how best to unit test.  I hope to document some of our issues and our treatment of them in this blog.

Leave a Reply

Your email address will not be published. Required fields are marked *