// insurance

A correct premium on the wrong date is a wrong premium. We test with the clock moved.

Insurance software is a set of money promises that must be recalculable on any date. We reprice real policy shapes before and after every change, and fail on any movement nobody asked for.

Start a one-month trial
ISO 27001:2022testing other people's software since 2018Reviewed on Clutch€20-45/hour
// what keeps you up at night, and what you get
"A rate change reprices policies we've already sold."
A sample of real policies repriced before and after every rate change, failing on any movement nobody asked for.Flows
"A backdated change breaks the refund maths."
Tests run with the clock moved: backdated changes, mid-term adjustments, cancellations and reinstatements.embedded testers
"Ten thousand renewal letters go out with one wrong figure."
Policy documents checked at volume, not one sample PDF.embedded testers
// four places insurance systems break
01 · effective dating

A backdated cancellation refunds the wrong amount

A policy is cancelled effective 1 July but keyed on 20 August. The refund routine counts the unexpired days from the date the transaction was posted, not the effective date. The customer is refunded for 134 days instead of 184, and nothing on screen looks wrong.

also: reinstatement three weeks later, leap years, 365 vs 366
annual premium120000term days365effective 01 Jul, keyed 20 Augrefund, effective date (184 d)60493refund, posting date (134 d)44055customer short16438
120000 x 184 / 36560493rounded once, at the end
FAILrefund counts from the posting date
PASSafter the fix
how we test itMove the clock, post the change late, and compare the refund with an independent pro-rata calculation. Repeat for every boundary: month end, leap day, term end.
await clock.set('2026-08-20')
const r = await cancel(policy, { effective: '2026-07-01' })
const expected = proRata(policy.premium, '2026-07-01', policy.termEnd)
expect(r.refund).toBe(expected)                // got 44055, want 60493
expect(ledger.imbalance()).toBe(0)
02 · rating

A rate change reprices business already written

Rate tables are versioned by effective date. Version 13 goes live on 1 March for new business. A mid-term change on a policy incepted in February looks up the table by today's date, reprices the whole policy at version 13, and the customer sees a premium jump they did not cause.

also: a quote saved yesterday and bound tomorrow
1 Febincept
1 Marv13 live
9 Maradd driver
9 Marexpected
RATED v12only the change, at v12 rates
how we test itReprice a fixed sample of real policy shapes before and after each rate deployment and fail on any difference. Then run mid-term changes after the switch date.
const before = await rating.priceAll(sample, { asOf: '2026-02-28' })
await deployRates('v13', { effective: '2026-03-01' })
const after = await rating.priceAll(sample, { asOf: '2026-02-28' })
expect(diff(before, after)).toEqual([])     // must not move
await clock.set('2026-03-09')
expect((await mta(policy, addDriver)).tableVersion).toBe('v12')
03 · claims ledger

A reserve movement posts to the ledger twice

A reserve increase of 5,000 is published to the finance interface. The ledger commits it but the acknowledgement times out, so the bus delivers the message again. With no idempotency key on the journal, the ledger posts it a second time and the claim shows 5,000 where the general ledger holds 10,000.

also: partial settlement, reopened claims, a payment that fails after the reserve moved
claimsbusledgerreserve +5000, claim C-77post reserve +5000journal committedack timeoutredeliver, at least oncejournal posted again
FAILclaim C-77: 5000 in claims, 10000 in ledger
how we test itRedeliver every finance message and reopen closed claims, then reconcile the claims sub-ledger to the control account, claim by claim.
ledger.dropAck('postReserve')
await claims.raiseReserve('C-77', 5000)
await bus.drainAll()                  // redelivery happens here
expect(ledger.balance('C-77')).toBe(5000)      // got 10000
expect(controlAccount.total()).toBe(claims.totalReserves())
04 · documents

One wrong figure on 10,000 renewal letters

The renewal batch reads the instalment amount from last year's premium field. The total payable is right and the instalment line is wrong, so every letter shows 12 payments that add up to less than the total. A single sample PDF passes review. The complaints arrive at volume.

also: aggregator feeds with latency budgets, bordereaux at month-end
Policy PX-20931 renewal 01 Nov 2026 Last year EUR 412.00 This year EUR 438.00 Payment plan 12 x EUR 34.33 Total payable EUR 438.00
10,000 LETTERSinstalments add to 411.96, not 438.00
how we test itGenerate the whole batch in a test environment, extract the text of every PDF and recompute each figure from the policy data. Totals must reconcile.
const pdfs = await renewals.generate(testBook)       // all of them
for (const pdf of pdfs) {
  const doc = parse(pdfText(pdf))
  const p = policyApi.get(doc.policyNo)
  expect(doc.total).toBe(p.premium)
  expect(sum(doc.instalmentList)).toBe(p.premium)      // last one adjusted
}

Illustrative examples built from defect patterns we test for. Not client data.

// on every pull request

Your code is written in hours. Our pipeline keeps up.

Pull requestfrom your coding agent
Flowsjourneys and fault injection
Security Toolkit15 scanners + 20 own checks
QA engineerconfirms every finding
BugBoardrelease report, Jira sync
// the regulation, in testing terms
regimewhere it actually breakswhat we run
IDDProduct information must reach the customer before the contract is concludedproduct information document present and correct before bind
DORAApplies to insurers too: resilience and ICT third partiesfailover, dependency timeouts, third-party outage drills
GDPRHealth data used in health and life underwriting is special category datasynthetic test data, production copies kept out of test
Solvency II reportingReporting pipelines a regulator readsreconcile output to an independently computed figure
// proof

What we bring to insurance

ISO 27001:2022money-and-dates testing1-month trial, first 2 weeks complimentary if you are not happy
  • The same money-and-dates testing we do for financial services: ledgers, rounding and time-dependent rules.

Insurance is newer ground for us than financial services, so we start with a one-month trial and you judge the work.

BUG-0297 · rating / mid-term adjustment · examplehigh

Adding a driver reprices the whole policy at the newest rates

  1. Take a policy incepted in February under table version 12
  2. Version 13 goes live on 1 March
  3. Add a driver on 9 March: the full premium moves from 412.00 to 438.00

Fix: Rate the change at the table version in force on the policy's effective date, not on the date of the transaction.

REQ-RATE-09TC-0942 addedJira POL-3310

A one-month trial on your rating and policy admin. The first two weeks are complimentary if you're not happy.

Start a one-month trial
// in depth: the long version
// 01

What actually breaks in insurance software

Two BetterQA colleagues discussing a test on a laptop at the office table

Effective dating. A policy is a state machine that moves through time, and most defects live in the gap between the date something happened and the date it takes effect. Mid-term adjustments, backdated endorsements, pro-rata refunds, cancellations with a reinstatement three weeks later. A test suite that only ever runs against today's date cannot see any of this. We test with the clock moved.

Rating. Rate tables are versioned by effective date, and a rate change deployed against the wrong version reprices business you have already written. Testing a rating engine means testing the table, the date the table applies from, and what happens to a quote saved yesterday and bound tomorrow. The arithmetic is the easy half.

Claims. First notification, reserving, payment, recovery and subrogation, salvage. Reserve movements land in the general ledger, so a claims defect is an accounting defect one hop later. The path that gets tested is the claim that gets paid. The paths that do not get tested are partial settlement, reopening a closed claim, and a payment that fails after the reserve has already moved.

Documents. Schedules, certificates, renewal notices. The single most visible defect class in this industry is a correct policy with a wrong document, because the document is the only thing the policyholder reads. Generating ten thousand PDFs where one figure is wrong is a complaint file, not a bug ticket.

Integration. ACORD messages between broker and carrier, aggregator and comparison feeds with hard latency budgets, bordereaux from delegated authority. These fail quietly and on a schedule, which means they fail at the end of the month when nobody is watching.

// 02

Test automation for insurance

Insurance is an unusually good fit for automation and an unusually bad fit for the way automation is normally done here.

The good fit: rate changes are frequent, and every one of them risks business already on the books. A regression suite that reprices a fixed sample of real policy shapes before and after a rate deployment, and fails on any movement nobody asked for, is worth more than any number of UI tests. That suite is data driven by construction. You build it once and feed it a matrix.

The bad fit: quote and bind journeys are long, branchy and rendered by portals that change quarterly, so UI-first automation in this market rots faster than anywhere else. We push as much as possible down to the rating service and the policy API, where the contract is stable, and keep the browser tests to the handful of journeys where the browser is the thing under test. Where we do drive a UI, we use Flows, our own recorder, which proposes selector fixes when a portal is redesigned, and an engineer approves each one.

More on both approaches: test automation, API testing, regression testing.

// 03

Test data, which is the part everyone underestimates

A BetterQA engineer typing at a standing desk in the office

Policy data is personal data, and in health, life and some liability lines it is special category data. Copying production into a test environment solves the realism problem and creates a much larger one.

So the first thing we usually build is not a test. It is a way to generate policy and claim data that is shaped like yours without being yours. Real distributions, real edge shapes, synthetic people. If that already exists in your organisation, we use it and say so. If it does not, we will tell you in week one that it is the prerequisite, because testing rating against four sample policies tells you almost nothing about a book of two hundred thousand.

// 04

Regulatory reporting we test

Solvency II reporting and IFRS 17 measurement are data pipelines with an audience of regulators. They can be tested the way any pipeline is tested: reconcile the output to an independently computed figure, and fail on any difference. We do that part.

We test that the software computes what your actuary specified.

Our certifications, and what each one is actually worth, are set out at certifications. ISO/IEC 27001:2022 is the relevant one here, because it governs how we handle your data, your credentials and your environments.

// 05

How we start, and what it costs

A one-month trial. We embed, learn the product, write tests and file real bugs against your actual software. The first two weeks are complimentary if you are not happy with what we deliver. You decide whether to carry on at the end of the first month. We do this because nobody can judge testing quality from a proposal, and every QA company's proposal reads the same.

After that, €20 to €45 an hour depending on seniority, commitment length and the mix of manual, automation and specialist work. Longer commitments move down the range. Every engineer on your product has shipped commercial releases before.

Included at no licence cost: BugBoard for test management, Flows for automation where an engineer approves each selector fix, Auditi for GDPR, WCAG and FDA auditing, BetterFlow so you can see where the hours went, and our AI Security Toolkit. We built all five because the off the shelf versions did not keep up with us.

Our engineers are in Cluj-Napoca, Romania, on GMT+2 and GMT+3 in summer. That covers the European working day and overlaps the start of the US East Coast day.

// 06

Talk to us

Tell us what you underwrite, how often you deploy, and what went wrong most recently. We will tell you whether this helps, and if it does not, we will tell you that instead.