From "Refactoring"
🎧 Listen to Summary
Free 10-min PreviewFundamental Practices for Building Robust Test Suites
Key Insight
Effective test suites rely on tests that are fully automatic and self-checking, providing simple pass/fail feedback. When developing tests, it is crucial to ensure they will fail when intended. This is achieved by temporarily injecting a fault into the code under test to confirm the test accurately exercises the code and can detect errors, then reverting the fault. This practice prevents false confidence in tests that might not genuinely catch bugs.
Test frameworks, such as Mocha, structure test code into 'describe' blocks for grouping test suites and 'it' blocks for individual tests. Within these blocks, assertion libraries like Chai allow verification using 'assert' or 'expect' styles (e.g., 'assert.equal(value, expected)' or 'expect(value).equal(expected)'). Tests typically follow a setup-exercise-verify pattern, where a fixture is prepared, an action is performed, and the outcome is verified, for example, by creating a Province object, modifying a Producer's production, and then asserting the shortfall and profit values.
To maintain test isolation and prevent intermittent failures, it is vital to create a fresh test fixture before each test execution, typically using a 'beforeEach' hook in test frameworks. This prevents tests from interacting through shared mutable objects, which could lead to non-deterministic results based on test run order. While rebuilding fixtures for every test might seem to impact performance, it is generally not a noticeable concern, and the debugging costs associated with shared mutable fixtures significantly outweigh any perceived speed benefits.
📚 Continue Your Learning Journey — No Payment Required
Access the complete Refactoring summary with audio narration, key takeaways, and actionable insights from Martin Fowler, Kent Beck.