State-based testing checks an observable change caused by the code under test. Instead of asserting the entry point’s returned value, call another function or inspect a sibling property to see whether the operation produced the expected state. section 1.5 section 8.3.1
Use the exit point to choose the test technique:
- Prefer a return-value test when the entry point directly provides the result. section 1.5
- Use a state-based test when the operation changes behavior or data visible through a sibling function or property. section 8.3.1
- Avoid replacing internal calls with mocks merely to verify that those calls happened; such tests overspecify implementation details. section 5.6.1 section 8.3.1
A state-based candidate
After invoking an entry point, make a follow-up call—or inspect an affected sibling property—and assert the resulting behavior. In PasswordVerifier4, verify() calls findFailedRules(), but no state affected by verify() is visible at the same scope, so this code is not a good candidate for state-based testing. Verifying the protected function call with a mock instead tests internal behavior and creates maintenance cost when implementation calls change. section 1.5 section 8.3.1
Listing 8.11 Production code that calls a protected function
export class PasswordVerifier4 {
private _rules: ((input: string) => boolean)[];
private _logger: IComplicatedLogger;
constructor(rules: ((input) => boolean)[],
logger: IComplicatedLogger) {
this._rules = rules;
this._logger = logger;
}
verify(input: string): boolean {
const failed = this.findFailedRules(input); #1
if (failed.length === 0) {
this._logger.info("PASSED");
return true;
}
this._logger.info("FAIL");
return false;
}
protected findFailedRules(input: string) { #2
const failed = this._rules
.map((rule) => rule(input))
.filter((result) => result === false);
return failed;
}
}
#1 Call to the internal function
#2 Internal function
Inspect the production flow from verify() to findFailedRules() to identify why an internal call is not itself the right state-based assertion point. section 8.3.1

