Assertion roulette happens when one test contains several assertions and an early failure stops later checks from running. The test report then shows only part of the problem, leaving hidden failures undiscovered until someone comments out assertions and reruns the test. That guessing game can create confusion and false confidence about what actually passes. section 2.5.9 section 4.4
The practical concern is not simply that a test has more than one assertion. It is that independent results cannot be reported independently when the first failing assertion aborts execution. A test may appear to identify one defect while another failure remains below the line that threw the error. section 2.5.9 section 4.4
Two checks, one interrupted test
A password verifier can return an error list that should contain one item and include a rule’s reason. Placing both checks in one test means a failure of the error-count check prevents the message check from running: const errors = verifier.verify('any value'); expect(errors.length).toBe(1); expect(errors[0]).toContain('fake reason'); If the first expectation fails, the second result is unknown. section 2.5.9
Split independent expectations into separately named test cases when each result deserves its own diagnosis. One test can verify that the error message contains the rule reason; another can verify that exactly one error was returned. Each test can then fail without blocking the other. section 2.5.9
Listing 2.12 Checking an extra end result from the same exit point
describe('PasswordVerifier', () => {
describe('with a failing rule', () => {
it('has an error message based on the rule.reason', () => {
const verifier = new PasswordVerifier1();
const fakeRule = input => ({ passed: false,
reason: 'fake reason'});
verifier.addRule(fakeRule);
const errors = verifier.verify('any value');
expect(errors[0]).toContain('fake reason');
});
it('has exactly one error', () => {
const verifier = new PasswordVerifier1();
const fakeRule = input => ({ passed: false,
reason: 'fake reason'});
verifier.addRule(fakeRule);
const errors = verifier.verify('any value');
expect(errors.length).toBe(1);
});
});
});
This listing separates the error-message expectation from the error-count expectation, making each outcome visible in its own test result. section 2.5.9
Splitting tests can introduce repeated setup: creating the verifier, defining a fake rule, adding it, and calling verify again. That duplication is a trade-off, not a reason to accept hidden failures. Shared setup such as beforeEach can reduce repetition after the tests have been separated. section 2.5.9
Assertion roulette also matters in interaction testing. If one verification fails, later mock verifications may not run, so several broken interactions can look like a single failure. Seeing the full set of failures helps avoid fixing the wrong behavior or fixing it in the wrong place. section 4.4
Do not confuse assertion roulette with the distinction between mocks and stubs. Assertion roulette describes failure reporting caused by test structure; mocks and stubs describe different kinds of test doubles. Both can appear in the same test, especially when interaction verifications are involved. section 4.4
