A regression test is a repeatable check that existing software behaviour still meets its requirements after a change. In quant work, it can reveal that a refactor, dependency update or bug fix has changed a valuation, risk calculation or data transformation that previously worked. The name refers to software getting worse after a change; it does not mean fitting a statistical model such as linear regression. NIST's definition focuses on protecting desired functionality from unacceptable changes.
“Regression” describes the test's purpose. A unit test of one calculation and an integration test of connected components can both serve as regression tests. A test need not originate from a past defect: a retained check for an already working feature also protects against regressions.
Turn a bug into a lasting check
Consider an invented software history, with fictional financial inputs. A function should value 2 whole shares at USD 100 per share. Its contract is quantity multiplied by price, giving USD 200. An earlier bug used addition and returned the raw number 102. Adding shares to dollars per share is dimensionally invalid: 102 is not a valid dollar valuation.
After repairing multiplication, retain a test fixture containing the inputs and the independently justified expected result. Here the oracle—the rule for deciding correctness—is the value of two separately held shares: USD 100 plus USD 100. Do not obtain the expected value by calling the same valuation function being tested.
The expected value stays fixed across versions. Reintroducing the original defect makes the retained test fail again; the fictional buggy output 102 has no valid valuation units.
This self-contained Python example uses the standard-library
unittest framework. Integer inputs deliberately avoid a floating-point tolerance decision.import unittest
def position_value(quantity: int, price_usd: int) -> int:
"""Value whole shares at an integer USD price per share."""
return quantity * price_usd
class PositionRegression(unittest.TestCase):
def test_two_shares_at_100_usd(self):
self.assertEqual(position_value(2, 100), 200)
result = unittest.TestResult()
PositionRegression("test_two_shares_at_100_usd").run(result)
print(f"tests={result.testsRun} failures={len(result.failures)} "
f"errors={len(result.errors)}")
# tests=1 failures=0 errors=0The summary is a deliberately compact report from
TestResult, not the framework's usual command-line display. The test method names the case and checks the result against the fixed oracle. In a project, put the test in the test suite and import the actual implementation; a copied function in a test file could pass while production code remains broken. Python's unittest documentation explains test cases, collection and execution.As a sensitivity check, replacing only the multiplication with addition makes this same test report
tests=1 failures=1 errors=0; the assertion identifies 102 != 200. This deliberate defective variant demonstrates that the check detects the targeted fault. Keep the repaired implementation and retain the test, rerunning it after later changes. The original report confirms the repair; future runs protect the repair.Preserve the contract, review the baseline
A saved output is useful only when someone has established why it is correct. Freezing a buggy historical output merely preserves a bug. For a numerical model, record the input conventions, source of the reference result and acceptance rule alongside the fixture. With floating-point arithmetic, justify an absolute or relative tolerance instead of widening it until a changed answer passes. For stochastic calculations, retain the seed and relevant environment details; repeatable random draws alone do not establish numerical accuracy.
When requirements deliberately change, review the expected result and its rationale together. Updating a baseline automatically to match the new implementation removes the test's independence. Conversely, insisting on obsolete output can block a correct change.
A passing fixture gives evidence about that case. It does not establish correctness for every position size, currency, invalid input or market scenario, nor validate a trading model's economic merit. Add cases for distinct failure risks, and use property-based testing when a relationship should hold across many generated inputs.
For numerical extensions, Testing Numerical Code develops pricing references, parity checks and tolerances. A public preview is available; the full lesson requires membership.
Sources
- NIST — Regression Testing: the change-protection definition.
- Python 3.14 — unittest: test cases,
assertEqualand result reporting. The example was executed with Python 3.14.4; the checked documentation is the current 3.14 series. - Microsoft Learn — Protection against regression: rerunning existing tests after changes to catch regression defects.