Behind every robust test suite lies infrastructure that prepares and cleans up the environment. Test fixtures provide a fixed, known starting state by supplying predefined data, object instances in a known configuration, or environment settings. The arrangement of fixtures is controlled through setup and teardown hooks. beforeEach and afterEach run before and after every test in a suite, while beforeAll and afterAll run once per suite, enabling fine-grained control over test isolation. Good fixtures are isolated, repeatable, and independent of test execution order, ensuring that each test begins with a clean slate.
Test isolation extends beyond fixtures: it means each test is fully independent, depending on no other test and affecting no other test. There should be no shared mutable state, and tests should be able to run in any order and still pass. Violations of isolation are a major source of flaky tests, which pass or fail intermittently without any change to the code. A related concept, test independence, requires that each test creates its own data and cleans it up rather than relying on the work of other tests. Hooks like beforeEach and afterEach are the primary mechanism for guaranteeing this property.
Tests are organized into test suites, which are collections of related test cases grouped by feature, module, or test type. Suites can be nested and run as units, allowing testers to target subsets of the codebase. The actual discovery, execution, and reporting of these tests is the job of a test runner, which finds test files by naming convention or configuration, executes them (often in parallel), and reports pass/fail status and timing. Examples include jest for JavaScript, pytest for Python, gradle test for Java, phpunit for PHP, and go test for Go. Each major language has its own prevalent framework: Jest for JavaScript offers zero-config setup with built-in mocking, snapshot support, and coverage reporting; pytest for Python favors plain assert statements and powerful fixtures with a rich plugin ecosystem; JUnit 5, or Jupiter, is the standard for Java with annotations like @Test, @BeforeEach, @AfterAll, and @ParameterizedTest; and Mocha, a flexible Node.js framework, uses describe and it syntax but typically requires separate libraries like Chai for assertions and Sinon for mocking.