Skip to main content

Testing

Philosophy: most tests are pure Python over shaped inputs (no DB, no HTTP), a small number are DB-backed, and one end-to-end script drives a full India run.

The layers

LayerSpeedLocation
Pure-logic pytestsub-second per filetests/test_*.py (most)
DB-backed pytestsecondstests that touch SessionLocal
e2e10-20sscripts/e2e_india.py

Run everything

cd apps/ledger
./.venv/Scripts/python.exe -m pytest tests/ -q

Run just the India suite

./.venv/Scripts/python.exe -m pytest \
tests/test_india_capital_gains.py tests/test_india_lrs_tax.py \
tests/test_india_fx_margin.py tests/test_india_remittance_exceptions.py \
tests/test_viewtrade_report_importer.py tests/test_india_nav.py \
tests/test_india_holdings_recon.py tests/test_india_schedule_fa.py \
tests/test_india_settlement_audit.py tests/test_india_broker_fees.py \
tests/test_india_webhooks.py tests/test_glomopay.py \
tests/test_india_reconciliation.py tests/test_provisioning.py -q

Run the e2e

python -m scripts.e2e_india

Drives: provisioning upsert → viewtrade sync → glomopay sync → reconciliation matched + mismatch cases → idempotency. Against a real ledger_ind DB (local).

Windows asyncpg flakiness

DB-backed pytest can flake on Windows due to asyncpg event-loop churn. The e2e script uses a different runtime pattern and is reliable there.

Adding a test

Every service module has a test_*.py. The pattern:

  1. Extract a PURE function (dict → summary) alongside the DB layer.
  2. Test the pure function with named-tuple inputs.
  3. If you need DB coverage, add an e2e case in scripts/e2e_india.py.

CI

Runs the full pytest on push. If you need to skip a slow test in CI, mark it with @pytest.mark.slow and configure CI to skip that marker.

Coverage

Not enforced as a gate. pytest --cov=ledger tests/ for a local report.