Skip to content

Test fixture

The controlled setup, data and cleanup that give a software test a known starting state, illustrated with fresh fictional holdings for each test.

A test fixture is the controlled preparation a software test needs, together with any cleanup afterward. It gives a quant calculation a known starting state: specified holdings, a fixed price snapshot, a prepared database or another deliberately chosen environment. When a test fails, that control helps distinguish a calculation defect from a change in the inputs.
A fixture can support a unit test, an integration test or a retained regression test. Those names describe what the test checks; the fixture describes what makes the check ready to run.

The starting state and the expected answer

Consider two fictional share holdings, valued at whole-dollar USD marks. There are no fees, FX conversions or contract multipliers in this example.

InstrumentQuantity (shares)Mark (USD per share)Value (USD)
A2100200
B350150
Total350
The holdings are fixture data. The expected USD 350 is the test oracle: the reference used to judge the result. Establish it independently, here by adding the USD 200 and USD 150 positions. Calling the valuation function twice and comparing its answers would check repeatability while allowing the same valuation error on both calls.

Small invented data are useful because every contribution is visible. They do not establish that the fixture resembles a realistic portfolio or covers stressed markets. Testing a missing mark, a short position or a currency mismatch requires explicitly designed cases and a stated contract for each.

Fresh objects prevent accidental test dependencies

Suppose one test increases A's quantity to 3 shares. Its expected value becomes USD 450: USD 300 for A plus USD 150 for B. A separate base-value test should still start from USD 350. Sharing a mutable holdings list would let the first test silently change the second test's experiment.
Fictional holdings A, 2 shares at USD 100, and B, 3 shares at USD 50, start each test independently at USD 350. Changing A to 3 shares in one test gives USD 450; the base-value test still receives USD 350.
Fictional holdings A, 2 shares at USD 100, and B, 3 shares at USD 50, start each test independently at USD 350. Changing A to 3 shares in one test gives USD 450; the base-value test still receives USD 350.
Each test receives new nested dictionaries. The quantity change belongs to one test and cannot leak into the other, whichever test runs first.
This self-contained Python example creates the list and its inner dictionaries afresh in setUp(), which unittest calls before each test method. It was executed with Python 3.14.4; it needs only the standard library.
import unittest def holdings_fixture() -> list[dict]: """Create fresh fictional share holdings for each test.""" return [ {"instrument": "A", "quantity": 2, "price_usd": 100}, {"instrument": "B", "quantity": 3, "price_usd": 50}, ] def value_usd(holdings: list[dict]) -> int: """Value integer share quantities at whole-dollar marks.""" return sum(row["quantity"] * row["price_usd"] for row in holdings) class HoldingsTest(unittest.TestCase): def setUp(self): self.holdings = holdings_fixture() def test_base_value(self): self.assertEqual(value_usd(self.holdings), 350) def test_quantity_change(self): self.holdings[0]["quantity"] = 3 self.assertEqual(value_usd(self.holdings), 450) suite = unittest.defaultTestLoader.loadTestsFromTestCase(HoldingsTest) result = unittest.TestResult() suite.run(result) print(result.testsRun, len(result.failures), len(result.errors)) # 2 0 0
The printed fields are tests run, failures and errors. Both tests also pass when run in the opposite order. Fresh construction matters at every mutable level: a shallow copy of the outer list would still share its inner dictionaries. Merely wrapping mutable contents in a tuple would not make those contents immutable.

Cleanup belongs to the fixture too

The in-memory example needs no external cleanup. A fixture that creates files or opens a database connection has a longer lifecycle. Acquire each resource and arrange its cleanup immediately. In unittest, addCleanup() registers cleanup callbacks that still run if a later step in setUp() fails; tearDown() runs only after successful setup. Python's TemporaryDirectory can manage a disposable directory through a context manager.

For a quant test, prefer an isolated working directory or test database over mutable production state. Record the price timestamp, currency and conventions needed to interpret a stored snapshot. A fixed snapshot makes that experiment repeatable; it does not make the snapshot current or guarantee that the chosen expected answer is economically correct.

For choosing numerical reference values and tolerances, Testing Numerical Code has a public preview; the full lesson requires membership.

Sources

  • Python: unittest — fixture terminology, per-test setup and cleanup semantics, including addCleanup().
  • Python: TemporaryDirectory — temporary-directory lifecycle. The current documentation consulted identifies itself as Python 3.15.2; the example above was run on Python 3.14.4.
Last updated
  • software testing
  • test fixtures
  • state isolation
  • quant software
← Back to the glossaryBack to top ↑