This post originated from an RSS feed registered with Agile Buzz
by Martin Fowler.
Original Post: Bliki: SelfTestingCode
Feed Title: Martin Fowler's Bliki
Feed URL: http://martinfowler.com/feed.atom
Feed Description: A cross between a blog and wiki of my partly-formed ideas on software development
Self-Testing Code is the name I used in Refactoring to refer to the practice
of writing comprehensive automated tests in conjunction with the
functional software. When done well this allows you to invoke a
single command that executes the tests - and you are confident that
these tests will illuminate any bugs hiding in your code.
I first ran into the thought at an OOPSLA conference listening to
"Beddara" Dave Thomas say
that every object should be able to test itself. I suddenly had the
vision of typing a command and having my whole software system do a
self-test, much in the way that you used to see hardware memory tests when
booting. Soon I was exploring this approach in my own projects and being
very happy with the benefits. A couple of years later I did some
work with Kent Beck and discovered he did the same thing, but in a
much more sophisticated way than I did. This was shortly before Kent
(and Erich Gamma) produced JUnit - a tool that became the
underpinning of much of thinking and practice of self-testing code
(and its sister: TestDrivenDevelopment).
You have self-testing code when you can run a series of automated
tests against the code base and be confident that, should the tests
pass, your code is free of any substantial defects. One way I think
of it is that as well as building your software system, you
simultaneously build a bug detector that's able to detect any faults
inside the system. Should anyone in the team accidentally introduce
a bug, the detector goes off. By running the test suite frequently,
at least several times a day, you're able to detect such bugs soon
after they are introduced, so you can just look in the recent
changes, which makes it much easier to find them. No
programming episode is complete without working code and the tests
to keep it working. Our attitude is to assume that any non-trivial
code without tests is broken.
Self-testing code is a key part of Continuous Integration,
indeed I say that you aren't really doing continuous integration
unless you have self-testing code. As a pillar of Continuous
Integration, it is also a necessary part of Continuous Delivery.
One obvious benefit of self-testing code is that it can
drastically reduce the number of bugs that get into production
software. At the heart of this is building up a testing culture that
where developers are naturally thinking about writing code and tests
together.
But the biggest benefit isn't about merely avoiding production
bugs, it's about the confidence that you get to make changes to the
system. Old codebases are often terrifying places, where developers
fear to change working code. Even fixing a bug can be dangerous,
because you can create more bugs than you fix. In such circumstances
not just is it horribly slow to add more features, you also end up
afraid to refactor the system, thus increasing TechnicalDebt, and
getting into a steadily worsening spiral where every change makes
people more fearful of more change.
With self-testing code, it's a different picture. Here people are
confident that fixing small problems to clean the code can be done
safely, because should you make a mistake (or rather "when I make a
mistake") the bug detector will go off and you can quickly recover
and continue. With that safety net, you can spend time keeping the
code in good shape, and end up in a virtuous spiral where you get
steadily faster at adding new features.
These kinds of benefits are often talked about with respect to
TestDrivenDevelopment (TDD), but it's useful to separate
the concepts of TDD and self-testing code. I think of TDD as a
particular practice whose benefits include producing self-testing
code. It's a great way to do it, and TDD is a technique I'm a big
fan of. But you can also produce self-testing code by writing tests
after writing code - although you can't consider your work to be
done until you have the tests (and they pass). The important point
of self-testing code is that you have the tests, not how you got to
them.
Increasingly these days we're seeing another dimension to
self-testing, with more emphasis put on monitoring in production. Continuous Delivery allows you to
quickly deploy new versions of software into production. In this
situation teams put more effort into spotting bugs once
in production and rapidly fixing them by either deploying a new
fixed version or rolling back to the last-known-good version.
This entry was originally published (in a much smaller form) on
May 5th 2005.