State-based testing verifies the state of the system after an operation completes. The checked state may belong to the system under test, a collaborator, or an out-of-process dependency such as a database or filesystem. section 6.1
Unlike output-based testing, which checks a return value, state-based testing checks changes produced by an operation. It is generally stronger than communication-based testing but weaker than output-based testing on resistance to refactoring and maintainability. section 6.0 section 6.2
Adding a product to an order
After calling AddProduct, the test checks that the order contains exactly one product and that it is the product supplied. The assertions verify the resulting collection rather than a return value or an interaction with a mock.
Use state-based tests with these constraints:
- Assert observable state rather than exposing private state solely to make testing possible. section 6.6
- Expect larger tests and moderate maintainability costs when assertions span several state properties. section 6.2
- Reduce assertion noise with helper methods or value objects, while recognizing that these techniques mitigate rather than eliminate the cost. section 6.6
- Prefer output-based testing when the code can be separated from side effects; retain state-based tests when that transformation is not reasonably worthwhile. section 6.4 section 6.5
Filesystem-backed audit system
A filesystem-coupled audit system can be tested by inspecting written files, but those tests are slow and difficult to maintain. Injecting a filesystem abstraction improves feedback, while refactoring AuditManager to return a FileUpdate enables concise output-based tests. This illustrates a migration path, not a requirement to eliminate every state-based test. section 6.4

