
42
also be because parts of the application’s behavior have unacceptable side effects or
dependencies that are impossible to satisfy in our development or test environment.
Modifying the SUT is a dangerous thing whether we are putting in Test
Hooks (page 709), overriding behavior in a Test-Specifi c Subclass, or replacing
a DOC with a Test Double. In any of these circumstances, we may no longer
actually be testing the code we plan to put into production.
We need to ensure that we are testing the software in a confi guration that is
truly representative of how it will be used in production. If we do need to replace
something the SUT depends on to get better control of the context surrounding the
SUT, we must make sure that we are doing so in a representative way. Otherwise,
we may end up replacing part of the SUT that we think we are testing. Suppose,
for example, that we are writing tests for objects X, Y, and Z, where object X
depends on object Y, which in turn depends on object Z. When writing tests for
X, it is reasonable to replace Y and Z with a Test Double. When testing Y, we can
replace Z with a Test Double. When testing Z, however, we cannot replace it with
a Test Double because Z is what we are testing! This consideration is particularly
salient when we have to refactor the code to improve its testability.
When we use a Test-Specifi c Subclass to override part of the behavior of an
object to allow testing, we have to be careful that we override only those meth-
ods that the test specifi cally needs to null out or use to inject indirect inputs. If
we choose to reuse a Test-Specifi c Subclass created for another test, we must
ensure that it does not override any of the behavior that this test is verifying.
Another way of looking at this principle is as follows: The term SUT is rela-
tive to the tests we are writing. In our “X uses Y uses Z” example, the SUT for
some component tests might be the aggregate of X, Y, and Z; for unit testing
purposes, it might be just X for some tests, just Y for other tests, and just Z for
yet other tests. Just about the only time we consider the entire application to be
the SUT is when we are doing user acceptance testing using the user interface
and going all the way back to the database. Even here, we might be testing only
one module of the entire application (e.g., the “Customer Management Mod-
ule”). Thus “SUT” rarely equals “application.”
Principle: Keep Tests Independent
When doing manual testing, it is common practice to have long test procedures that
verify many aspects of the SUT’s behavior in a single test. This aggregation of tasks is
necessary because the steps involved in setting up the starting state of the system for
one test may simply repeat the steps used to verify other parts of its behavior. When
tests are executed manually, this repetition is not cost-effective. In addition, human
testers have the ability to recognize when a test failure should preclude continuing
Also known as:
Independent
Test
Chapter 5 Principles of Test Automation