Proving It Works, Not Just Believing It
Running a program and reading the output by eye works fine until it has more than one path through it. Write an assertion that checks the answer for you, and let it fail loudly the moment the code stops agreeing with itself.
Worth reading first: Naming a Piece of Work
Running a program and reading the output by eye works fine until it has more than one path through it. Write an assertion that checks the answer for you, and let it fail loudly the moment the code stops agreeing with itself.
assert is the smallest test you can write
$ >>> def add(a, b):$ ... return a + b$ ...$ >>> assert add(2, 3) == 5$ >>> assert add(2, 3) == 6$ Traceback (most recent call last): ...$ AssertionErrorassert condition does nothing at all if condition is true, and raises an AssertionError the instant it is false. That is the entire mechanism every testing tool in Python — including pytest — is ultimately built on top of.
A test that only ever passes is not testing anything
A test is only proof of something if it is possible for it to fail. Check three cases below, each testing a small function for finding the largest number in a list — see which ones actually earn their place.
A real test. It picks a specific input, states the one correct answer, and would fail loudly if largest ever returned 3 or 1 instead.
Not a real test. Both sides call the exact same function on the exact same input, so this passes even if largest is completely broken — it is only checking that the function agrees with itself, not that it is correct.
A real test, and an important one — the empty-list case is exactly the kind of edge a normal run-and-eyeball check tends to skip entirely.
Naming a test after what it proves, not what it calls
def test_returns_the_maximum_value(): assert largest([3, 1, 4]) == 4 def test_empty_list_returns_none(): assert largest([]) is Nonetest_largest says only which function is involved. test_returns_the_maximum_value says what the test actually proves — when it fails months later, the name alone tells you what broke, before you have read a single line of the assertion.
Key takeaways
- assert condition does nothing if the condition is true, and raises AssertionError immediately if it's false.
- A test only proves something if it's possible for it to fail — checking a function against a call to itself never can.
- Testing an edge case, like an empty list, catches the exact class of bug an eyeball check on normal input tends to miss.
- Naming a test after what it proves (test_empty_list_returns_none) tells you what broke on failure, faster than a name that only says which function it calls.