Dependent Test – State Sharing via Global Variables
Description
A Dependent Test also occurs when tests share mutable global state and rely on implicit execution order to pass. In this scenario, the outcome of a test depends on whether a previous test has modified a shared variable and whether that state has been properly reset.
This form of dependency is especially dangerous because the test framework may execute tests in a different order, in parallel, or selectively, causing tests to fail intermittently or produce misleading results.
Identified Dependent Test Patterns
The following patterns are explicitly considered Dependent Test smells in this catalog.
1. Shared Global Variables Without Reset
Any mutable global variable (int, String, List, Map, bool, double, etc.) that is:
- Modified in one test, and
- Read or modified in another test, and
- Not reset in
setUp()ortearDown()
creates an execution-order dependency.
This includes primitive types and collections.
Why this is a smell
- Tests become order-dependent.
- Running a single test in isolation may fail.
- Running the full suite may pass or fail depending on execution order.
- Parallel execution becomes unsafe.
2. Multiple Tests Writing and Reading the Same Global State
When two or more tests interact with the same global variable, the dependency grows with each additional test.
Example Patterns (Conceptual)
-
Test A increments a global counter
-
Test B assumes the counter starts at zero
-
Test A sets a message
-
Test B expects the message to be empty
-
Test A adds items to a shared list
-
Test B checks the list size
-
Test C expects the list to be empty
Each additional test increases the dependency chain, multiplying the number of Dependent Test smells.
3. Collections Shared Across Tests
Shared collections (List, Map, Set) are particularly problematic.
They are considered Dependent Test smells when:
- Items are added or removed in one test
- Another test assumes a specific collection state
- No reset is performed between tests
This includes cases where:
- One test fills a cache
- Another test reads from the cache
- Another test assumes the cache is empty
Even if the expected value matches, the test is still dependent.
4. Boolean Flags Used Across Tests
Boolean flags used to represent state transitions are also a source of dependency.
A smell exists when:
- One test sets a flag to
true - Another test assumes the flag is already
true - A later test sets it back to
false
This creates implicit sequencing requirements, which violate test independence.
5. Numeric Values Modified Incrementally
Numeric globals (int, double) used in arithmetic across tests are Dependent Tests when:
- One test assigns or modifies the value
- Another test performs calculations based on the current value
- A later test expects the initial default value
These tests cannot be executed independently or reordered safely.
What Is NOT Considered a Dependent Test
The following cases are explicitly excluded from Dependent Test detection:
1. Global Variables Reset in setUp()
If a global variable is fully reset before each test, it does not create a dependency.
Example characteristics:
- Reset happens in
setUp() - All tests start from the same known state
- No test relies on side effects from previous tests
2. Local Variables Inside Tests
Variables declared inside a test body are always safe.
They:
- Exist only within the test scope
- Cannot be accessed by other tests
- Do not introduce shared mutable state
3. Immutable or Recreated Test Data
Objects or collections created fresh inside each test do not introduce dependencies, even if they contain similar data.
Summary of Detection Rules
A test must be flagged as a Dependent Test if:
- It reads or writes mutable global state, and
- That state is accessed by another test, and
- There is no reset mechanism ensuring isolation
The number of Dependent Test smells increases with the number of tests interacting with the same shared state.
Note
This catalog treats state-based dependencies as first-class Dependent Test smells, even when:
- Tests pass consistently in a local environment
- The dependency is not immediately obvious
- The shared value happens to match the expected result
The key criterion is test independence, not execution success.