Quiz
Warm-up from lesson 3-2: the spec says accounts lock after 5 failed logins. Which attempts counts should your boundary tests probe?
Writing the test first
So far you wrote code, then tests. Test-driven development (TDD) flips the order, for two concrete reasons: tests written after the code tend to be shaped by what the code happens to do instead of what the spec demands, and writing the test first forces you to decide the exact expected behavior before your brain is invested in an implementation. Plenty of working engineers run this loop daily on core logic — pricing, parsing, date math. You work in a short loop with three beats:
- Red: write one small test for behavior that does not exist yet, run it, watch it fail
- Green: write the smallest amount of code that makes the test pass
- Refactor: clean the code up while the tests stay green, exactly like lesson 1-2
Then repeat with the next behavior. Each loop takes a few minutes.
Why insist on seeing red first? Because a test you have never seen fail is unverified. If it would pass even against broken code, it protects nothing. Watching it go red, then green after your change, proves the test actually watches the behavior you think it does.
Code exercise · python
Run this cautionary tale. The function is an empty stub, yet the test PASSES — because assert not result is true when result is None. This test has never been seen red, and it is watching nothing: it would pass against a completely broken implementation. TDD's red beat exists precisely to catch tests like this before you start trusting them.
Quiz
In the green step, you write the smallest code that passes. Your test says fizzbuzz(3) == "Fizz" and you could pass it with return "Fizz". Why is that hard-coded return acceptable for now?