I asserted the whole returned object and the test broke on every cosmetic change. Assert on the thing the promise is actually about, not on everything that happens to be in the answer.
Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.
Data Flow
You pick the narrowest fact that states the promise, assert that fact, and the test fails only when that behaviour breaks.
1State the promise
↓
2Pick the narrowest fact
↓
3Assert that fact
↓
4Fail only on real break
Why this worksAssert the narrowest fact
A test that checks the whole object is glued to the object's shape. Change a field name and the test breaks even though the behaviour is fine. Assert the specific value or property the promise is about, so the test fails only when the behaviour actually breaks.
Equality is not the only assert
Beyond == you have in, <, >, is None, and pytest.raises. Pick the one that states the promise. For a list you might assert its length or that an item is in it, not that it equals a literal, unless the exact order is the point.
Examples
Assert the result
assert title_case("hello") == "Hello"
Assert on the value the function promises. This says one thing: the output is Hello. If the function returns that, the promise holds.
Assert a property
assert len(words("a b c")) == 3
You do not need the whole list, you need its length. Asserting the smallest fact that proves the point keeps the test about behaviour, not shape.
Assert an error
with pytest.raises(ZeroDivisionError):
divide(1, 0)
Some promises are about failing. This one says divide must raise when the divisor is zero. A test can require a crash.
Words this lesson uses
Each one is defined here on this site. Open the entry for the full definition and the other words it points at.