About unittests
Have you ever done maintenance on a large
application and broken something because you changed something,
somewhere? Or worse, only noticed the breakage when a user
mailed you? Have you ever begun writing an application, but were
unable to complete it because the whole castle of cards
collapsed due to excessive fragility?
It has probably happened to you, and it
certainly has happened to me. Testing software is a boring
chore, and besides, everything has to be finished yesterday, or
today at the latest. However, not testing
will cost you a lot of time, too, and it's more fun to program
than to bug-hunt. It would be best if automated testing could be
made part of the edit-compile-crash cycle.
This has occurred before to a lot of people,
but the honor of ‘inventing' automatic unit-testing
belongs to Erich Gamma and Kent Beck - familiar names to
developers everywhere. They started writing unit-test frameworks
for SmallTalk, moving on to Java and other languages.
The idea is simple but ingenuous: first the
developer writes his test, then the class that will make the
test work; the process is repeated until the created code fits
the application you're developing. All the while, you will get
instant feedback from a small GUI app that runs your tests and
shows you a green progressbar when everything works as intended,
and a horrible, unfriendly red progressbar when a test fails.
You can also run the unittests without a gui, but it isn't as
much fun.
Writing tests takes a bit of getting used-to,
and it is something more easily learned when
working together with someone who has done it before. However,
once you get around to it, it is definitely addictive.
Unit-testing using the
unittest.py framework also departs from
what people are used to doing when testing: namely, writing
scripts that simulate user input, such as mouse-clicks. Those
scripting solutions are quite often so fragile that they are
worse than useless. It is far better to explicitly code tests
for the back-end of your application, guaranteeing that the
interaction between backend and GUI is correct, as opposed to
trying to deduce bugs from apparent errors at the GUI
front.
In sum, the advantage of unit-testing is:
you know you can depend upon the behavior of your components,
and whenever you change a component, you will be alerted to that
change by failing tests. In short, you will be able to trust
your software at a relatively low level.
There a few disadvantages, too. You might
be lulled into a false sense of security: if you change your
unit-tests along with the code, then you can no longer be sure
that your components fit your system, for you have just changed
their behavior. A unittest is a kind of contract about the
behavior your code exposes to the outside world. Changing the
contract one-sidedly is a guarantee for breaking
relations.
It's also quite difficult to find a good
division between unit-tests and functional tests. Functional
testing is mostly done from a user perspective; unit-tests test
the behavior of your classes, but functional tests test the
behavior of the application. There is currently no way to
automate functional testing.
Cynics have noted that the running of
unittests has negated all the progress made in creating fast
compilers, and even virtually compilation-less languages such as
Python. Indeed, running a full testsuite can take a long time.
Fortunately, Pyunit is very
fast.
Lastly, watching the bar stay green is
addictive in itself, and you might be tempted to run working
tests over and over again...