Programming with GUTs

Better Software Magazine
Volume-Issue: 
2008-06
Summary:

Since tests are commonly viewed in terms of offering quantitative feedback on the presence or absence of defects in specific situations, Good Unit Tests need both to illustrate and define the behavioral contract of the unit in question. Do you have GUTs?

Looking around at some of the writing on the subject, both online and off, you could be forgiven for thinking that test-driven development (TDD) is just another way of saying testing, simply a synonym for programmer testing , or a fancy way of promoting plain ol' unit testing . It is not that these concepts do not have value-they do-it's that the arbitrary use of the term TDD decreases both the value of TDD and of other points of view. Not all testing is unit testing, and not all unit testing derives from TDD. As Alistair Cockburn noted in his blog earlier this year [1]:

Very many people say "TDD" when they really mean, "I have good unit tests" ("I have GUTs"?) Ron Jeffries tried for years to explain what this was, but we never got a catch-phrase for it, and now TDD is being watered down to mean GUTs.

Well, now at least there is a catch phrase for it! The distinction being drawn is both clear and useful: TDD is a way of doing something--i.e., it is a process; GUTs are an outcome--i.e., they describe an artifact and a quality of that artifact.

What Do You Want From Your Tests?
Tests are commonly viewed in terms of offering quantitative feedback on the presence or absence of defects in specific situations. They are, however, in a position to offer much more than this.

For example, our tests can give us feedback on how loosely coupled our code is. Some portion of any nontrivial system is necessarily not unit testable: The portion of the code that must interact across the system boundary may be integration testable, but it is not unit testable. This is the code that may be mocked out for purposes of unit testing other parts of a system, but should also be tested in its own right.

So, if there is some portion of our code that is necessarily not unit testable, how much should be unit testable that isn't? If the only code-facing tests we can write are integration tests, the chances are good that our code is too tightly coupled, no matter what dewy-eyed vision we may hold of its architecture. Furthermore, this also says something about the relationship between test quality and code quality: How good our set of unit tests can be is constrained by the quality of the production code's architecture.

For us to consider our tests good, we may want other things from them, such as coverage. However, because it's less familiar territory for many programmers, let's keep exploring qualitative rather than quantitative feedback. When we look at test code, do we expect to see something written only for machine execution, or is human consumption also a key consideration? In the blurb for their conference session, "Are Your Tests Really Driving Your Development?" [2], Nat Pryce and Steve Freeman make clear the importance of the human audience:

Everybody knows that TDD stands for Test Driven Development. However, people too often concentrate on the words "Test" and "Development" and don't consider what the word "Driven" really implies. For tests to drive development they must do more than just test that code performs its required functionality: they must clearly express that required functionality to the reader. That is, they must be clear specifications of the required functionality. Tests that are not written with their role as specifications in mind can be very confusing to read. The difficulty in understanding what they are testing can greatly reduce the velocity at which a codebase can be changed.

This consideration is perhaps more explicit and more

File: 
AttachmentSize
Programming_with_GUTs.pdf354.6 KB

About the author

Kevlin Henney's picture
Kevlin Henney

Kevlin Henney is an independent consultant and trainer based in the UK. He provides consultancy and training in programming techniques, software architecture, and development process. Kevlin is co-author of two recent books on patterns, A Pattern Language for Distributed Computing and On Patterns and Pattern Languages.

Upcoming Events