I was skeptical about the benefits of Unit Testing, like many developers I
work with. I work with a lot of development teams as a teacher and trainer. I’d
seen some teams benefit, but others got nothing but headaches. My latest project
has me convinced that rigorous automated Unit Testing is a software development
best practice. It saves time, and enhances your ability to create great
software. Let me share my experiences on a large ongoing project. It convinced
me, and I think it will convince you too.
We introduced unit testing on
my current large project, a change from my previous project. Comparing the
progress of the two projects has sold me on its benefits. We are several months
in and well past the point that I can keep all but the high level architecture
in my head at one point in time. The typical scenario on past projects was that
I would write some amount of code, one to fifteen lines of code and run the
project. I have often included a button on forms that would fill out all of the
fields with the minimum required data to speed up the manual testing process.
Right here was one issue – I was putting testing code into the production
application. The testing process consisted of poking at the application and
trying to break things. I would store up two or three issues before trying to
run because this process was so painful. Of course, this took ages because I
would find something wrong and would have to quit testing, fix the code and
rerun. I had no idea how broad changes would be if I fixed a given component.
The further down in the architecture, like a database helper class, the scarier
this became. Even to test the particular UI bit that I knew that it affected, I
would have to log into the app, navigate to the page with the error and then
fill out the form and so on. Since I couldn’t possibly know everywhere that was
affected this could take a lot of time and it still wouldn’t be
Somewhere in here, I would have flash backs to my mainframe days
where you’d write code, hand walk it, submit the 10 new lines of code to the
compiler and wait. You’d have the results of your compile printed out 2-4 hours
later, depending on whether or not the big iron was under load. The next step
was to correct the spelling because none of the tools had IntelliSense and start
the whole process over again. Throw in a lunch and that was your whole day. You
had accomplished the task of compiling 10 new lines of code. The next day, you’d
get to test it and then fix it again.
These practices impede forward progress
on a project so that I can either laugh or cry. I stay sane by realizing
first that I’m not, by any stretch of the imagination, telling war stories that
you haven’t personally felt as well and second, there is a better way now.
My current project is much different because of testing, testing and
more testing. I know exactly what I have and haven’t broken a mere matter of
seconds after making the change. Let’s start by talking about the database
helper class scenario. I make a change to one of the methods in the database
helper class. Now, rather than running and guessing as to what’s changed, fixed
or broken, I’ve got automated tests that test that particular method in several
different ways directly. I pass in several types of good data and bad data. If
it stopped here, that would be good, but it still might have broken something
else that I didn’t realize. In addition, I’ve got automated tests for the data
classes that use the utility classes. And I’ve got automated tests for the
middleware that uses those data classes. And I’ve got automated tests for the
ASP.NET UI. And the best part is that all of the backend and middleware tests
run in about thirty seconds. The ASP.NET code actually makes the HTTP calls and
renders the HTML, parses it and so on so they take a touch longer. Even running
all of the tests takes just a couple of minutes.
At that point, I can
feel free to move on and write more code without that same knot in my stomach
that I’ve broken something that I didn’t know about. I’m not spending time
repeating myself and typing in the same meaningless test input into the UI over
and over. I am using the computer to do that for me. It makes for more
repeatable, consistent tests that actually get executed.
Now, that being
said, I don’t believe that the tests that I’m writing can replace the testing
that a business analyst, the user or a quality assurance team does. When the
tests that I run pass, that means that the code does what I meant for it to do.
There are a number of limitations with this. First, it could be that I forgot a
possible scenario. Second, the code that does what I meant for it to do might
not do what the user or business analyst meant for it to do. If we have
communicated well, it will be close but it’s possible that there a
misunderstanding which will have lead me down the wrong path.
haven’t bought into all of the TDD philosophy. I still don’t write my tests
before I write the code. I just haven’t been able to get my head around that
concept yet. I have trouble thinking about all of the ways that the code is
going to be used and writing tests and then writing the code. I’m thinking that
I will make that transition at some point for some tests.
I’ve been thinking
that I should take my use cases and start from there writing tests. In future
posts, I’ll talk about my thought process here.
One of the keys to a
good unit testing experience is having the proper tools. I’ve put together what
I think is a good toolset, at least for ASP.NET, that is able to test the vast
majority of what I need to test. I’ll talk about this toolset and how you can
get started on unit testing yourself in future posts.