Contents

Engineering Craft › Testing

Test Fixture

Setup data or state that tests rely on.

Also known as: fixture, test fixtures, pytest fixture, setUp

A test fixture is the setup that a test needs before it can run: data, objects, a database, a temporary file, a fake service. It also covers the cleanup afterwards. Fixtures keep the “arrange” part of tests out of every test body.

import pytest

@pytest.fixture
def cart():
    c = Cart()
    c.add(Item("kettle", 30))
    return c                          # the test receives it by name

def test_total(cart):
    assert cart.total() == 30

@pytest.fixture
def db():
    conn = create_test_database()
    yield conn                        # the test runs here
    conn.close()                      # cleanup after the test
let cart;
beforeEach(() => { cart = new Cart(); });     // runs before each test
afterEach(() => { cleanup(); });

Why use them

  • No repeated setup copy-pasted across tests.
  • Cleanup is guaranteed, even when a test fails.
  • Clear scope: per test, per file, or once per run.

Scope matters

  • Per-test fixtures are fresh every time, so tests can’t affect each other. This is the safe default (test isolation).
  • Shared (per-module or per-session) fixtures are faster for expensive setups like a database container, but need care so tests don’t leave dirty state, for example by rolling back a transaction after each test.

Cautions

  • Hidden dependencies. A fixture with a lot of data makes a test hard to understand. Keep what the test depends on visible, and create only what’s needed.
  • Over-sharing. A giant shared fixture that everything uses becomes fragile.
  • Order dependence: a test shouldn’t rely on data a previous test created.
  • Realistic but minimal: use builders or factories for objects with many fields (test data builders).
  • Test databases need resetting between tests (test database).