Checking That It Works
Writing code is only half the job; the other half is gaining confidence that it is correct. Testing does this by running the program on chosen inputs and comparing its actual output against the expected output you worked out independently.
A single test case is a pair: an input, and the output it should produce. A useful test suite covers three kinds of input:
- Typical cases — ordinary, representative inputs (does
double(4)give8?). - Edge cases — the boundaries where bugs love to hide: zero, an empty list, the first and last valid index, the largest allowed value, a negative number.
- Invalid cases — inputs the program should reject or handle gracefully (non-numeric text where a number is expected).
The mindset is adversarial: a good tester actively tries to break the program, not to confirm it works. Passing a hundred typical cases proves little if a single overlooked edge case (an empty input, a zero, an off-by-one boundary) still crashes it.
Testing famously cannot prove a program correct — you cannot try every possible input — but a well-chosen suite can reveal the presence of bugs cheaply and repeatably. Automated tests are especially valuable because they can be re-run after every change (a regression test) to confirm nothing that used to work has broken.
Common pitfall: testing only "happy path" typical inputs and skipping edge cases. Most real bugs surface at the boundaries — an empty list, a zero, the maximum value, the first or last index. A test suite without edge cases gives false confidence; deliberately probe the boundaries.