Test Data Management in Banking
Generating Realistic, Compliant Datasets Without Touching Production PII
Generating Realistic, Compliant Datasets Without Touching Production PII
As a senior tester on banking systems, I've sat in more than one incident review where the root cause traced back to a test environment that didn't behave like production — not because the code was wrong, but because the data was. A masking script that flattened every account balance to round numbers. A synthetic customer set with no realistic distribution of edge cases: no near-threshold KYC flags, no accounts sitting right at a fraud-rule boundary, no genuinely messy legacy records. The tests passed. The behaviour they validated wasn't the behaviour production would actually see.
Test data management in banking is not a data privacy checkbox sitting next to your GDPR compliance program. It is a testing discipline in its own right, and treating it as an afterthought to masking production exports is how realistic-looking test failures make it past QA and into a regulator's incident report instead.
The default approach at most institutions starts with taking a production extract and masking it — replacing names, obfuscating account numbers, tokenising national ID fields. This solves the immediate compliance problem: no real PII sits in a lower environment. It does not solve the testing problem, and it introduces a few of its own.
Masked production data still requires production access to generate in the first place, which means every refresh cycle re-opens the exact PII exposure surface you're trying to close. It also degrades in usefulness the moment masking breaks referential consistency — a masked customer ID that no longer matches across the core banking system, the fraud engine, and the CRM produces integration test failures that have nothing to do with the code under test. And critically, masked data is a snapshot. It reflects last quarter's customer distribution, not the edge cases your next release actually needs to be tested against.
Synthetic data generation solves a different problem than masking does, and the two are complementary, not interchangeable. Masking is appropriate when you need data that mirrors a specific production state for regression or migration testing. Synthetic generation is appropriate — and usually preferable — when you need data engineered to exercise specific behaviours, at volume, without a production dependency at all.
There's also a coverage gap that masking can't fix by definition: masked data can only ever contain the edge cases that happened to occur in the production window you extracted from. If your fraud rules changed last month to catch a new pattern, no amount of masking a six-month-old production snapshot will produce a test record that exercises the new rule. Testers relying solely on masked data end up writing manual test fixtures to patch the gap anyway — at which point the question is why the whole dataset isn't being generated with that same intentionality from the start.
The bar for synthetic test data in banking is higher than "looks plausible." It needs to preserve the statistical properties that make production behaviour reproducible: the actual distribution of transaction amounts, the correlation between customer segment and product holding, the realistic frequency of the edge cases that trigger your fraud, AML, and credit risk logic. Uniform random generation fails this bar immediately — real transaction data is heavy-tailed, real customer portfolios are correlated across fields, and a generator that ignores those properties will pass tests that production will fail.
In practice, this means building generation logic off statistical profiles extracted from production — distributions, correlations, and boundary frequencies — rather than off the raw records themselves. This is a meaningful distinction from a compliance standpoint: a statistical profile (mean transaction size by segment, correlation between account age and product count, frequency of near-threshold flags) contains no individual customer information, while still faithfully reproducing the shape of the data that testing depends on.
We've had good results using Claude, prompted against these extracted profiles, to generate the synthetic record sets themselves — writing generation scripts with GitHub Copilot assisting on the boilerplate, and using Claude to reason through edge-case coverage: given a fraud rule set, which record shapes are needed to exercise every branch, including near-miss cases that sit just inside and just outside a threshold. This is where a senior tester's judgment still matters most — a model can generate volume and can be prompted toward specific edge cases, but knowing which edge cases actually matter for a given rule engine, and which correlations in the data are load-bearing for a given test suite, is domain expertise that has to be applied to the prompt, not delegated away from it.
A banking test environment is rarely one system. A synthetic customer needs a consistent identity across core banking, the payments engine, the fraud detection layer, and any downstream reporting or reconciliation pipeline — the same reconciliation and event-driven patterns we've covered elsewhere in this series apply directly here, since a test dataset that breaks referential consistency between a Kafka event stream and its downstream consumer produces failures indistinguishable from a genuine integration bug.
This is usually the point where synthetic data generation projects underdeliver: the generator produces excellent individual records but no mechanism to propagate a consistent synthetic identity and its associated state across every system under test. The fix is architectural rather than a generation-technique problem — a synthetic data service that owns identity generation centrally and is queried by every downstream test data need, rather than each team generating its own synthetic dataset independently and hoping the IDs happen to line up.
In practice, that means the synthetic identity service is the source of truth for a given test customer's state — account status, KYC flag, product holdings — and every consuming system (core banking, the fraud engine, the CRM, any reconciliation job reading off a Kafka topic) reads that state rather than maintaining its own copy. When a test scenario needs a customer whose KYC status changes mid-scenario, that transition is written once, upstream, and every downstream consumer observes the same consistent version of events. Without this, teams end up debugging phantom failures where two systems under test simply disagree about which state a shared test customer is in — a failure mode that has nothing to do with the feature being tested and everything to do with how the test data was assembled.
Under GDPR, the presence or absence of PII in a dataset isn't the only relevant question — re-identification risk from combinations of quasi-identifiers (birth date, postcode, employer, product mix) can reconstruct an individual even from data with no direct identifiers present. A synthetic dataset built from real statistical profiles needs to be evaluated for this risk explicitly, not assumed safe because no name or account number appears in it. Differential privacy techniques applied at the profile-extraction stage — adding calibrated noise before the statistical profile is derived, rather than after synthetic records are generated — are the more defensible approach for institutions that need to document this for an auditor or under DORA's operational resilience testing requirements, which extend to how test environments themselves are managed.
A mature test data management approach in banking treats synthetic generation as infrastructure, not a per-project script: a maintained, centrally owned service that produces statistically realistic, referentially consistent, re-identification-risk-assessed datasets on demand, engineered from the start to cover the edge cases your specific rule engines and regulatory obligations require — not retrofitted after a masking approach has already shown its limits in a failed audit or a missed edge case in production.
Getting this right from the outset, rather than discovering the gaps through an incident review, is the difference between a testing function that gives your institution genuine confidence in a release and one that gives false confidence dressed up as a green test suite.