Skip to content

Chapter 5 of 7

Test Infrastructure and Frameworks

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.

All chapters
  1. 1Test Types and Strategy
  2. 2TDD and BDD
  3. 3Test Doubles
  4. 4Writing and Structuring Tests
  5. 5Test Infrastructure and Frameworks
  6. 6Measuring Test Quality
  7. 7Specialized Testing and CI/CD

Drill it

Reading is not remembering. These come from the Testing Tdd deck:

Q

What is a unit test?

A unit test verifies the behavior of a single, isolated piece of code (e.g., a function or method). Key characteristics:Tests one logical unit in isolationDepen...

Q

What is an integration test?

An integration test verifies that multiple components work correctly together. Unlike unit tests, it exercises real interactions:Tests communication between mod...

Q

What is an end-to-end (E2E) test?

An E2E test simulates real user workflows through the entire application stack. It validates the system from the user's perspective:Uses tools like Playwright,...

Q

What is the Test Pyramid?

The Test Pyramid is a testing strategy that recommends:Base (most): Unit tests — fast, cheap, numerousMiddle: Integration tests — moderate speed and countTop (f...