Part 6 of 6 · Chapter 3 of 4

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.

Advanced10 min read

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

Terminal
$ >>> def add(a, b):$ ...     return a + b$ ...$ >>> assert add(2, 3) == 5$ >>> assert add(2, 3) == 6$ Traceback (most recent call last):  ...$ AssertionError

assert 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.

Naming a test after what it proves, not what it calls

test_largest.py
def test_returns_the_maximum_value():    assert largest([3, 1, 4]) == 4 def test_empty_list_returns_none():    assert largest([]) is None

test_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.