Skip to content
Crayon CS

Make it comfy

Lesson style

Quick mode shows the key picture, a summary and the practice. Good for a refresher.

Theme
Font

Both fonts are designed to be easy to read. Some readers with dyslexia prefer Lexend.

Text size
Spacing
Animations

Lesson 20 of 26 · about 16 min

Testing and debugging

Testing is trying your code on carefully chosen inputs to find bugs. Debugging is the detective work of finding why a bug happens, one experiment at a time.

🧭 What you need first: When things go wrong

The story

A bridge engineer doesn’t wait for traffic to find out whether a bridge holds. They test it: normal loads, a heavy truck, a full traffic jam, the edges near the supports. Testing is trying to break your own work before someone else does.

When something does break, you become a detective. A good detective doesn’t accuse random suspects. They gather clues, form a theory (“the butler had the key”), test it, and only then make the arrest. Debugging is detective work: each experiment narrows down where the bug can be hiding.

Another way: tasting while you cook

A good cook tastes the soup as they go, not only when it’s served. Running your tests after every change is tasting as you go. You catch the “too much salt” moment immediately, when it’s easy to fix.

Another way: the rubber duck

Programmers keep a rubber duck on their desk and explain their code to it, line by line. Halfway through explaining, they usually spot the bug. Saying exactly what you think the code does reveals where it doesn’t.

Play with it

Hunt the bug

This function should return the largest number in a list. It looks right, and it even works on the first example. Run it, then add your own test lines at the bottom until you find an input that breaks it.

(Spoiler, try it first: a list of only negative numbers like [-5, -2, -9] returns 0, which isn’t even in the list. Starting biggest at nums[0] fixes it.)

Name it

The real words

Testing

  • A test case is an input plus its expected output. A test suite is a collection of them.
  • Choose test cases deliberately:
    • Typical inputs: what you expect most of the time.
    • Edge cases: empty list, zero, one item, all items equal, negative numbers, very large numbers.
    • Boundaries: just below, at and just above a limit (for “grade A is 90+”, test 89, 90 and 91).
  • Black-box testing: tests chosen from the specification alone, without looking at the code. Glass-box testing: tests chosen by looking at the code, so every branch and loop path runs at least once.
  • Automate it: assert largest([-5, -2]) == -2 fails loudly when something breaks. Python’s doctest even lets you put examples inside docstrings and run them as tests. Re-running all tests after every change is called regression testing.

Debugging

  • Debugging is a search. The steps:
    1. Reproduce it: find a small input that always triggers the bug.
    2. Read the error message from the bottom up: what went wrong, and on which line.
    3. Hypothesize: “I think biggest starts at the wrong value.”
    4. Experiment: add a print() or step through with a tracer, and see if the evidence fits.
    5. Fix one thing, then re-run all the tests.
  • Three kinds of bugs: syntax errors (Python can’t read it), runtime errors (it crashes), logic errors (it runs but gives the wrong answer, the sneakiest kind).
  • When stuck: explain it out loud (rubber duck), take a break, or cut the problem in half: check whether the bug happens before or after the midpoint of the code.
Build it

Write tests, then fix the bug

average(nums) has a bug: it crashes on an empty list (it should return 0). It also has a second, sneakier bug. Write at least 3 asserts that test it (including edge cases), then fix both bugs.

Challenge

Choose the best tests

A function is_adult(age) should return True for 18 and over. Which set of tests is best?

Remember it

What's the FIRST step in debugging?

Got it?

Finish the lesson to color it in on your map and collect its concept cards.

Did this lesson click?