Skip to content

Integration test

A test of connected software components, illustrated by an offline CSV-to-holdings valuation and the limits of its coverage.

An integration test checks whether connected software components work together according to an expected contract. In quant work, it can catch a valuation function receiving strings where it expects numbers, a price column mapped to the wrong field, or a currency convention lost between ingestion and calculation.
The important question is which real boundaries the test crosses. A test can cover a small group of collaborating components; it need not run an entire application or contact a live market feed.

Follow the data across a boundary

Consider a fictional holdings file. Instrument A has 2 shares priced at USD 100 per share; B has 3 shares priced at USD 50 per share. Their values are USD 200 and USD 150, for a total of USD 350, before fees or other adjustments.
The following offline example connects Python's CSV reader, explicit conversion to typed tuples, and a valuation function. The test fixture is an in-memory CSV stream. No final valuation is substituted by a mock.
import csv from decimal import Decimal from io import StringIO def parse_holdings(text: str) -> list[tuple[str, int, Decimal]]: """Convert the fixture's named CSV fields into holdings.""" reader = csv.DictReader(StringIO(text)) return [(r["instrument"], int(r["quantity"]), Decimal(r["price_usd"])) for r in reader] def value_holdings(rows: list[tuple[str, int, Decimal]]) -> Decimal: """Value shares using USD-per-share prices.""" return sum((quantity * price for _, quantity, price in rows), Decimal("0")) def test_csv_to_valuation() -> Decimal: """Exercise ingestion, conversion and valuation together.""" text = "instrument,quantity,price_usd\nA,2,100\nB,3,50\n" rows = parse_holdings(text) assert rows == [("A", 2, Decimal("100")), ("B", 3, Decimal("50"))] total = value_holdings(rows) assert total == Decimal("350") return total print(f"USD {test_csv_to_valuation():.2f}") # USD 350.00
DictReader supplies text fields; int and Decimal perform the conversions here. The annotations document the interface and do not enforce it at runtime. Decimal values constructed from these integer strings make the displayed arithmetic exact. The intermediate assertion checks the records as well as the final total: a correct aggregate alone can hide offsetting mistakes.
Offline integration boundary connects CSV ingestion, typed holdings and valuation. A has 2 shares at USD 100 per share, B has 3 at USD 50, and the asserted total is USD 350.
Offline integration boundary connects CSV ingestion, typed holdings and valuation. A has 2 shares at USD 100 per share, B has 3 at USD 50, and the asserted total is USD 350.
A fictional integration test exercises the real CSV reader, conversion and valuation functions together. The boundary stops before files, market feeds and reports.

This example assumes the named columns, integer share quantities and finite USD prices. A production ingestion contract needs explicit decisions and tests for missing fields, malformed values, duplicates, currency, timestamps and any permitted short positions. A passing happy-path example does not establish those behaviours.

Unit, integration and end-to-end scope

Teams draw these boundaries differently. A useful convention is:

Test scopeWhat it exercises in this example
Unit testValuation logic supplied with already constructed holdings, without CSV ingestion.
Integration testCSV reading, conversion and valuation connected as shown above.
End-to-end testA complete defined workflow, such as uploading a file through an application and checking its resulting report.

An end-to-end test can include several integrations; the labels do not form a universally fixed taxonomy. Name the included components, entry point, output and replaced dependencies so readers know what the test actually demonstrates.

Replacing the CSV parser with a stub that returns prebuilt tuples would remove the parser-to-valuation boundary from this check. Replacing the final valuation with a fixed 350 would remove the calculation too. Such replacements may be useful for other tests, but they provide no evidence that the replaced components integrate correctly.

Read a pass within its limits

This test checks an in-memory path. It says nothing about file permissions, text encoding at a file boundary, database drivers, network authentication or market-data freshness. Add tests in the relevant environment when those contracts matter. Keep setup controlled and restore state between cases so one test's changes cannot determine another's result.

Passing unit tests helps diagnose failures, but does not prove a component correct for inputs it has never seen. An integration failure can still originate inside one component. Likewise, a correct USD 350 total validates this fixture and these assertions, not a pricing model, an operational deployment or every possible holding.
For choosing stronger input cases, Testing Strategies: Black-Box and Glass-Box Testing develops specification-based boundaries and code-path checks. Its public preview is open; the full lesson requires membership. Treat prior unit testing and bottom-up integration as useful workflows, rather than prerequisites in the definition of an integration test.

Sources

Last updated
  • software testing
  • quant software
  • data pipelines
← Back to the glossaryBack to top ↑