Script Valley
Debugging: A Systematic Approach
Testing as a Debugging ToolLesson 5.1

How to write a failing test that proves a bug exists

test-driven bug fixing, red-green cycle, failing test as specification, assert-first pattern, test isolation

The Test Before the Fix

Before fixing a bug, write a test that fails because of that bug. This does three things: it proves you understand the bug precisely enough to specify the correct behavior; it gives you a clear definition of done (the test must go green); and it prevents the bug from returning silently.

Writing the Failing Test

Identify the exact input that triggers the bug and the exact output you expect instead of what currently happens. Write a unit test that asserts the expected output. Run it -- it must fail (red) before you touch any production code.

// Bug: applyDiscount returns wrong result when coupon is a string
const assert = require('assert');

function applyDiscount(price, coupon) {
  return price - coupon; // current broken code
}

// This test must fail FIRST
assert.strictEqual(applyDiscount(100, '20'), 80);
// AssertionError: 10020 !== 80 -- good, the test is red

// Fix the function
function applyDiscount(price, coupon) {
  return price - parseFloat(coupon);
}

assert.strictEqual(applyDiscount(100, '20'), 80); // green

Test Isolation

The test must fail only because of the bug, not because of external dependencies. If the function under test calls a database or API, mock those dependencies. A test that fails intermittently due to network issues is not a reliable signal of the bug.

Up next

How to write regression tests so bugs never come back

Sign in to track progress

How to write a failing test that proves a bug exists โ€” Testing as a Debugging Tool โ€” Debugging: A Systematic Approach โ€” Script Valley โ€” Script Valley