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.
