Financial automation fails in ways that ordinary CRUD tests rarely cover. A duplicated callback can post the same effect twice. A stale approval can commit a superseded suggestion. A frontend may display “completed” while the provider is still processing the request.
Testing these systems with production exports creates a second problem: financial and customer data should not be copied into public demos, sample repositories, or ad-hoc development environments.
A safer approach is to build synthetic state fixtures around the workflow rules you need to prove.
1. Design fixtures around decisions, not random rows
Randomly generated amounts and descriptions may help with volume tests, but they do not prove domain behavior. Each fixture should represent a question the system must answer.
Examples:
- Can a draft move to review?
- Can a rejected suggestion be posted?
- What happens when the same provider event arrives twice?
- Does a missing evidence reference block approval?
- Is a correction recorded without erasing the previous state?
A compact JSONL case can describe both the starting state and the expected result:
{
"case_id": "duplicate_callback_001",
"entity_type": "synthetic_collection",
"initial_state": "provider_pending",
"event": "provider.confirmed",
"idempotency_key": "synthetic-event-001",
"expected_state": "confirmed",
"expected_audit_events": 1,
"contains_real_customer_data": false
}
The identifiers and values above are synthetic. They describe behavior, not a real transaction.
2. Keep a transition matrix beside the data
The dataset is more useful when the allowed and forbidden transitions are explicit.
| From | Event | Expected result |
|---|---|---|
| draft | submit_for_review | review_required |
| review_required | approve | approved |
| approved | post | posted |
| rejected | post | rejected with domain error |
| posted | approve | posted with idempotent response |
The negative rows matter as much as the happy path. A finance-critical service should fail clearly when a transition is invalid; it should not silently coerce the state or pretend that the operation succeeded.
3. Test retries as first-class scenarios
External operations are retried in normal production conditions. Your fixtures should include:
- the first valid delivery,
- an identical retry,
- a retry with the same key but conflicting payload,
- an out-of-order event,
- a provider timeout followed by a later confirmation.
For an identical retry, assert more than the HTTP status. Verify that:
- the financial effect exists once,
- the stored provider reference is stable,
- no duplicate audit event was appended,
- the response is consistent with the first successful application.
4. Assert auditability, not only final state
A test that checks only status === "posted" misses important failure modes. Also assert the transition history:
initial state
-> requested event
-> guard evaluation
-> authorized actor or policy
-> resulting state
-> audit event
For corrections and reversals, preserve the original event and add a compensating action. The fixture should make the expected history reconstructible.
5. Test API and UI semantics together
A backend may correctly return provider_pending while the interface labels it “Completed.” That is still a product defect.
Use the same fixture vocabulary across layers:
- API contract tests verify status and error semantics.
- Service tests verify guards, idempotency, and audit events.
- UI smoke tests verify the exact user-visible label and allowed actions.
Avoid optimistic finance messaging that hides uncertainty. If the provider state is unknown, the interface should say so.
6. Version the fixture contract
Synthetic data is still an interface. Give the schema a version and record why fields change.
A practical fixture repository can include:
-
schema_version, - JSONL for event-oriented cases,
- CSV for inspection and simple tooling,
- a README defining every field,
- a license,
- checksums or release tags for reproducibility.
When a workflow rule changes, add a new case or version instead of silently rewriting the evidence used by earlier tests.
A public reference set
We published a small, fully synthetic reference set for auditable, human-in-the-loop financial workflow states: FISCUS AI Financial Workflow State Fixtures.
It is intended for testing and demonstration, not as accounting data and not as a substitute for domain-specific validation. The fixtures contain no real customer transactions.
At FISCUS AI, we use this state-first perspective to reason about controlled automation for Turkish SME financial operations.
This article provides general technical information and is not accounting, tax, legal, or investment advice.
Top comments (0)