TITLE: TDD and Encapsulated Objects
AUTHOR: Eugene Wallingford
DATE: August 05, 2004 11:04 AM
DESC: hpw TDD does and does not encourage tight encapsulation
-----
BODY:
Does test-driven development help us to build software with a higher
degree of encapsulation? I feel like it does when I write code.
But this is the sort of claim that, when made in front of students,
can be exposed as either wrong or more complex than it first appears.
That's because it depends on assumptions and skills that not all
programmers hold.
How might test-driven development help us to build
better-encapsulated software? When we write tests first, we have an
opportunity to think about our code in terms solely of its interface
because we haven't written the implementation yet! In an object-oriented
program, the test involves sending a message to an object in order to
see whether the object behaves as expected. The object's class may
may be partially implemented, but not the behavior we are testing.
And we are supposed to be thinking about just the requirement at
hand, not anything else.
But how can we go wrong? If we become sloppy, we can fall into the
trap of writing a test that causes a change in the object's state
and then verifies that the expected change has occurred. This often
requires adding a public accessor to the object's interface that is
otherwise unnecessary. Even you don't intend for client programmers
to use the method, it's now there. One of the lessons of interface
design is that, if it's there, clients will use it.
It's more than just sloppiness that can lead us astray, though.
Testing some behaviors is not straightforward because they involve
outside resources (say, a web connection) or non-trivial collaborations
(say, a network error). Often it's easier to write a state-based
test than a behavior-based test. But those kinds of tests usually
leave me feeling unfulfilled. That feeling is my test telling me to
do better.
The idea of
mock objects
developed in the XP community as a way to support behavior-driven testing
in the face of such difficulties. But even mock objects aren't a guarantee
that we will write well-encapsulated code. Martin Fowler wrote a recent
article discussing the common confusion of
mocks
with stubs.
I do think that TDD encourages and supports well-encapsulated code --
but only if the programmer understands the
Tell,
Don't Ask
principle for designing objects. And practices it faithfully. And uses
mock objects (or their equivalent in your programming style) for the
tough cases. That's a lot of assumptions built into a simple claim.
But most knowledge works that way.
How can you support yourself in those assumptions? Pair programming!
Those XP practices really do add up to something more than their parts.
-----