Skip to content

A risk based testing approach for fintech: the scoring matrix we use

Our risk based testing approach for fintech scores each test item by impact per failure (money moved, regulatory exposure, customer harm) and by likelihood (change frequency, integration count), and multiplies the two scores into a risk level that sets test depth. In our practice, a top-level money or regulatory item never drops below the second of four depth tiers.

Mira Kowal, Senior QA engineer, lending, BNPL and wealthtechPublished Updated

What the ISTQB definition fixes, and what it leaves to you

The ISTQB Glossary (term version 3, undated, read 2026-09-22) defines risk-based testing as "A test approach in which the management, selection, prioritization, and use of test activities and resources are based on corresponding risk types and risk levels." The risk level entry reads "The measure of a risk defined by risk impact and risk likelihood."

The ISTQB Foundation Level syllabus v4.0.1, dated 15 September 2024, gives the method in section 5.2.3: "In the quantitative approach the risk level is calculated as the multiplication of risk likelihood and risk impact. In the qualitative approach the risk level can be determined using a risk matrix." The same section says the analysis results are used to "Determine the test techniques to be employed and the coverage to be achieved" and to "Estimate the test effort required for each task".

Section 5.2.2 lists "incorrect calculations" among product risks, and "Loss of revenue, trust, reputation" and "Criminal penalties" among their consequences. The syllabus does not say how to score them; on a lending product, that choice decides whether a late fee rule gets a boundary suite or a smoke check.

Why fintech impact needs three columns

A single severity field ranks a crashed settings screen and a double interest posting on similar terms. We split impact into three columns, each with its own owner and recovery path:

  • Money moved per failure. An accrual job that runs twice after a retry posts a second day of interest to every active loan, and repeats each night until reconciliation catches it.
  • Regulatory exposure. The annual percentage rate (APR) on an offer screen moves no money. Regulation Z still states that the APR "shall be determined in accordance with either the actuarial method or the United States Rule method" (12 CFR 1026.22(a)(1), eCFR up to date as of 2026-09-18).
  • Customer harm. A repayment debited twice can overdraw the borrower's bank account at another bank, a loss that never appears in the lender's ledger.

We take the highest of the three as impact. An average lets a harmless display column dilute a level 4 money column.

Likelihood gets two inputs from the repository and architecture diagram: how often the code changed, and how many external systems the item touches. Each integration adds failure paths that the main path never runs: timeouts, duplicate events, late webhooks, and returns.

The scoring matrix we use

This is our practice. ISTQB defines risk level from impact and likelihood; the scales, the highest-of-three rule, the tiers, and the floor below are ours.

ScoreMoney moved per failureRegulatory exposureCustomer harmChange frequencyIntegrations touched
1No money movesNo named ruleCosmetic defectNo change in the last 12 monthsNone
2One account, reversible the same dayPartner bank or lender contract termDefect with a workaroundChanged in the last 12 monthsOne
3Many accounts, or a ledger postingNamed rule on timing or records, or a network ruleWrong amount shown or chargedChanged in at least 6 of the last 12 monthsTwo or three
4Funds leave the platform, or a batch or settlement amount is wrongNamed rule on what the customer is charged or toldLost access to funds, or a missed paymentChanged in this releaseFour or more

The formula:

  • Each column takes the highest band that matches.
  • Impact is the highest of money, regulatory, and customer.
  • Likelihood is change plus integrations, divided by 2, rounded up.
  • Risk is impact times likelihood, from 1 to 16.
  • Tier D1 covers risk 12 to 16, D2 covers 8 to 9, D3 covers 4 to 6, and D4 covers 1 to 3.
  • Floor: an item with money or regulatory at 4 gets at least D2.
TierWhat we testWhen it runsEvidence kept
D1Written specification with worked reference values, boundary tests on every input, an independent reference model, and failure paths per integrationEvery merge, plus a reconciliation replay before releaseRun report per release with build and environment
D2Boundary tests on documented limits and one failure path per integrationEvery mergeRun report per release
D3Main path plus one boundary per inputNightlyCI history
D4Smoke checkRelease suiteCI history

The worked rows describe a synthetic consumer lending product. Keep the CSV in the repository next to the tests:

Data
item,money,regulatory,customer,change,integrations
daily interest accrual on instalment loans,3,3,3,3,2
late fee after the grace period,2,4,3,2,3
repayment collection by ACH debit and returns,4,3,4,3,4
APR on the loan offer screen,1,4,3,2,2
early payoff quote,3,3,3,1,2
lead routing to partner lenders,2,2,2,3,4
statement PDF layout,1,1,1,2,1
disbursement to the borrower bank account,4,2,4,1,3
adverse action notice,1,4,2,1,1

The script reads that file as risk_matrix.csv and prints the tier per item:

Python
import csv, math

TIERS = [(12, "D1"), (8, "D2"), (4, "D3"), (1, "D4")]

def score(row):
    m, r, c = (int(row[k]) for k in ("money", "regulatory", "customer"))
    f, n = int(row["change"]), int(row["integrations"])
    impact = max(m, r, c)
    likelihood = math.ceil((f + n) / 2)
    risk = impact * likelihood
    tier = next(t for floor, t in TIERS if risk >= floor)
    floor = (m == 4 or r == 4) and tier in ("D3", "D4")
    return impact, likelihood, risk, "D2" if floor else tier, "*" if floor else " "

with open("risk_matrix.csv", newline="") as fh:
    rows = [(row["item"], *score(row)) for row in csv.DictReader(fh)]

for item, i, l, s, t, mark in sorted(rows, key=lambda r: (r[4], -r[3])):
    print(f"{t}{mark} {s:>2} = {i} x {l}  {item}")

Output with Python 3.13.1:

Output
D1  16 = 4 x 4  repayment collection by ACH debit and returns
D1  12 = 4 x 3  late fee after the grace period
D2   9 = 3 x 3  daily interest accrual on instalment loans
D2   8 = 4 x 2  APR on the loan offer screen
D2   8 = 2 x 4  lead routing to partner lenders
D2   8 = 4 x 2  disbursement to the borrower bank account
D2*  4 = 4 x 1  adverse action notice
D3   6 = 3 x 2  early payoff quote
D4   2 = 1 x 2  statement PDF layout

Two rows show why the rules exist. The adverse action notice scores only 4, because its template rarely changes and touches no external system. Regulation B states that an adverse action notification "shall be in writing" (12 CFR 1002.9(a)(2), eCFR up to date as of 2026-09-18). Under 1002.9(d), a creditor that "did not receive more than 150 applications during the preceding calendar year" satisfies the section with oral notifications. Either way the floor lifts it to D2. The early payoff quote sits at D3 while its code is stable; set change to 4 in the release that touches it, and risk becomes 9 and the item moves to D2.

How we run the matrix in a release

  • Score items, not features. One row is one calculation, one state transition, or one file format. A single "repayments" row hides the higher-scoring return path.
  • Re-score on three triggers. A pull request that touches the item raises change. A new partner bank or processor raises integrations. A launch in a new state or country raises regulatory exposure.
  • Review the CSV diff in the pull request. A tier drop then sits next to its cause.
  • Write failure paths for D1 before any defect appears. The ACH row gets tests for a return after the funds were marked available, a duplicate debit file, and a late return code.

For D1 calculation rows, the independent reference model and boundary suite come from financial calculation testing. The accrual row's leap year and month-end cases are in our interest accrual and day count guide. Where no scored inventory exists yet, a QA audit and test strategy engagement builds one and turns it into a risk-based test strategy and roadmap. The failure patterns behind the lending rows are on our consumer lending testing page.

Scope your testing

Send FintechAssuranceLabs your product, segment, money flows, and the standards that need evidence, and get a proposed test scope with its deliverables.

Scope your testing