Regression Testing
What it is
Section titled “What it is”A regression test verifies that behaviour which used to work still works after a
change. Every git push, dependency bump, refactor or config tweak risks breaking
something unrelated — regression testing is the net that catches it before users do.
before ──► change ──► regression suite ──► behaved as before? │ pass │ └ fail → a regression └ ship with confidenceRegression testing is not a test level (unit, integration, E2E) but a purpose: any test at any level can be a regression test. The practice is usually automated and lives in CI, growing over time as each fixed bug earns a permanent test.
When to use it / when to avoid it
Section titled “When to use it / when to avoid it”Use it for
- After every code change, before merge or release
- After upgrading a dependency, framework or runtime
- Whenever a bug is fixed — add a test so it can never regress silently
- Refactors that should preserve observable behaviour
Avoid it when
- You are verifying one specific fix in isolation → a sanity test is cheaper and sharper
- You need to confirm the build even boots → start with a smoke test
- The “test” only re-asserts the implementation details of the code you just wrote
Frameworks & tools
Section titled “Frameworks & tools”| Tool | Ecosystem | Notes |
|---|---|---|
| Vitest / Jest | JS/TS | Snapshot tests catch unintended output drift |
| Playwright | Multi | Replay critical journeys on every build |
| pytest | Python | Parametrised regression cases; pytest-regressions |
| Go testing | Go | go test ./...; golden files for output comparison |
| JUnit 5 | Java/JVM | Suites + tags; run the full suite on every PR |
| xUnit / NUnit | .NET | dotnet test across the whole solution |
| Robot Framework | Python | Keyword suites run on every release candidate |
| BackstopJS / Percy | Multi | Visual regression (screenshot diffing) |
| ApprovalTests | Multi | Golden-master / approval testing |
| k6 | Multi | Performance regression baselines |
Quick setup
Section titled “Quick setup”npm install -D vitest @vitest/coverage-v8npx vitest run --coveragepip install pytest pytest-regressionspytest -qgo test ./... -count=1go test ./... -update # regenerate golden files after intended change<!-- Maven: fail the build if any test regresses --><plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <testFailureIgnore>false</testFailureIgnore> </configuration></plugin>dotnet test --no-build --verbosity normalExample
Section titled “Example”import { describe, it, expect } from 'vitest';import { formatInvoice } from './invoice';
describe('formatInvoice (regression)', () => { it('keeps the established output format', () => { expect(formatInvoice({ total: 1200, currency: 'USD' })) .toMatchInlineSnapshot('"$12.00"'); });});def test_invoice_format_stable(file_regression): result = format_invoice(total=1200, currency="USD") file_regression.check(result)func TestInvoiceFormatRegression(t *testing.T) { got := FormatInvoice(1200, "USD") golden, _ := os.ReadFile("testdata/invoice.golden") if got != string(golden) { t.Fatalf("regression: output changed\nwant %q\ngot %q", golden, got) }}import static org.junit.jupiter.api.Assertions.assertEquals;import org.junit.jupiter.api.Test;
class InvoiceRegressionTest { @Test void formatStaysStable() { assertEquals("$12.00", Invoice.format(1200, "USD")); }}using Xunit;
public class InvoiceRegressionTests{ [Fact] public void FormatStaysStable() { Assert.Equal("$12.00", Invoice.Format(1200, "USD")); }}Anti-patterns & best practices
Section titled “Anti-patterns & best practices”- Add a test with every bug fix. A fixed bug without a regression test will come back.
- Prefer behaviour over snapshots alone. Snapshots catch drift but say nothing about intent; pair them with explicit asserts.
- Keep the suite fast enough to run every time. If it is too slow to run, it will not run.
- Do not assert implementation details. Tests bound to private structure fail on harmless refactors.
- Update goldens deliberately. A golden change should be a reviewed, intended change, never a blind regenerate.
- Quarantine, do not ignore, flaky tests. A red suite people ignore is not a safety net.
Self-assessment quiz
Section titled “Self-assessment quiz”Self-assessment quiz
Pick one answer per question, then press Check answers.