
Variation: Incremental Tests
We may also use Shared Fixtures when we have a long, complex sequence of
actions, each of which depends on the previous actions. In customer tests, this
may show up as a work fl ow; in unit tests, it may be a sequence of method calls
on the same object. This case might be tested using a single Eager Test (see As-
sertion Roulette on page 224). The alternative is to put each distinct action into
a separate Test Method (page 348) that builds upon the actions of a previous test
operating on a Shared Fixture. This approach, which is an example of Chained
Tests (page 454), is how testers in the “testing” (i.e., QA) community often
operate: They set up a fi xture and then run a sequence of tests, each of which
builds upon the fi xture. The testers do have one signifi cant advantage over our
Fully Automated Tests (see page 26): When a test partway through the chain
fails, they are available to make decisions about how to recover or whether it is
worth proceeding at all. In contrast, our automated tests just keep running, and
many of them will generate test failures or errors because they did not fi nd the
fi xture as expected and, therefore, the SUT behaved (probably correctly) differ-
ently. The resulting test results can obscure the real cause of the failure in a sea
of red. With some experience it is often possible to recognize the failure pattern
and deduce the root cause.
10
This troubleshooting can be made simpler by starting each Test Method with
one or more Guard Assertions (page 490) that document the assumptions the
Test Method makes about the state of the fi xture. When these assertions fail,
they tell us to look elsewhere—either at tests that failed earlier in the test suite
or at the order in which the tests were run.
Implementation Notes
A key implementation question with Shared Fixtures is, How do tests know about
the objects in the Shared Fixture so they can (re)use them? Because the point of
a Shared Fixture is to save execution time and effort by having multiple tests use
the same instance of the test fi xture, we’ll need to keep a reference to the fi xture
we create. That way, we can fi nd the fi xture if it already exists and we can inform
other tests that it now exists once we have constructed it. We have more choices
available to us with Per-Run Fixtures because we can “remember” the fi xture we
set up in code more easily than a Prebuilt Fixture (page 429) set up by a different
program. Although we could just hard-code the identifi ers (e.g., database keys) of
the fi xture objects into all our tests, that technique would result in a Fragile Fix-
ture. To avoid this problem, we need to keep a reference to the fi xture when we
create it and we need to make it possible for all tests to access that reference.
10
It may not be as simple as looking at the fi rst test that failed.
Shared
Fixture
Chapter 18 Test Strategy Patterns
322