Testing lab
Session goal
Students internalize that routes are callable functions, write one honest assertion per feature, and read a failing test as information rather than as punishment. The lab's centerpiece is diagnosing planted bugs with tests, which converts testing from a chore into a power.
Audience and timing
Students with a multi-page, form-using app of their own (after the story maker, ideally during the quiz game). One 50 minute session.
Prerequisites
Comfort calling functions with made-up arguments, and a working
app in every editor. Students have seen assert_state in
tutorial code without necessarily writing one.
Materials
- Test a feature: the reference recipe.
- A starter file you distribute: a small working app (a treat
counter with a feed route and a reset route works well) with
three planted bugs: one logic slip (
+ 2instead of+ 1), one wrong page text, and one route that forgets to returnindex(state)and builds a slightly wrong page instead. - The debug panel's Tests tab on the projector.
Plan
- The reveal (10 min). Project a route, then call it in
plain Python:
feed(State(0)), no server, no browser. Let that sink in; routes were functions all along. Wrap the call inassert_state(feed(State(0)), State(1)), run, and show where the green result lands in the Tests tab. - Bug hunt (20 min). Distribute the starter. The rule:
every bug must be convicted by a test before it is fixed;
a test that fails, then the fix, then the same test green.
Pairs work well. The wrong-text bug forces
assert_has, the logic bugassert_state, and the third teaches that tests catch what eyeballs skim past. - Your app, your tests (15 min). Everyone writes two
assertions for their own project: one
assert_stateon a logic route, oneassert_hason a page. The recipe page is open; you circulate for expected-values-copied-from-output, the anti-pattern worth catching live. - Wrap (5 min). Name the habit (one feature, one test, same day) and where it lives in their project workflow (Test as you go).
Checks for understanding
- "Why did
assert_state(feed(State(0)), State(1))not need the server running?" (Routes are functions; the call is the test.) - "Your test expected
State(2)and gotState(2)but still shows the page differing. Which assertion should this feature have used?" (Two assertions test two different things; state and page are separate claims.) - "When is it fine for a test to fail?" (When the code is wrong, and when the test is stale after a deliberate change; both answers matter.)
Common stumbles
- Producing expected values by running the code and copying its answer, which proves nothing; require hand-worked expectations in the bug hunt.
- Whole-page comparisons that shatter on any edit; steer to
assert_haswith one meaningful needle, and save page freezing for the finishing tutorial. - Fear response to red output; the bug hunt's framing (a red test is a conviction, and you are the detective) is the antidote, so protect it in your language all session.
Extensions
Test a failure path (the reset route on an already-zero state);
freeze one finished page via the History tab and read the
generated assert_equal; write a test first for the next
planned feature and watch it go green when the feature lands.
Assessment ideas
Collect the convicted-and-fixed starter file: three failing tests turned green tells the whole story. On the final project, grade for one honest assertion per feature, which makes this session's habit worth points for the rest of the term.