Test discovery and assertions
corebeginnerpytest finds tests automatically: files named test_*.py or *_test.py, functions named test_*, classes named Test*. Inside a test, a plain assert is enough — pytest rewrites it to show exactly what values did not match.
Think of it as
unittest needs you to say assertEqual(a, b) so it knows how to explain a failure. pytest instead reads your plain assert a == b at import time and rewrites it internally to capture both sides — you write ordinary Python, and the detailed failure message comes for free.
What we're doing: Show a passing assertion, then a failing one, to see pytest's assertion-rewriting output for real.
- 6
- A plain assert — no assertEqual needed. pytest rewrites this at collection time to capture both sides for the failure report.
def test_add_wrong_expectation():
> assert add(2, 2) == 5
E assert 4 == 5
E + where 4 = add(2, 2)Why this works: pytest's assertion rewriting parses the test file and replaces plain assert with introspection code, so a failure shows the ACTUAL computed value (4) next to the expected one (5) and even shows where 4 came from — all without writing assertEqual(add(2, 2), 5).
Naming a test helper function test_* by accident
Wrong
Better
What you see: pytest reports an extra, unexpected "test" that fails or errors — usually with a confusing "fixture not found" or a silent pass that means nothing, since a helper wasn't written to be run standalone.
Why: Discovery is purely name-based — pytest cannot tell a genuine test from a same-named helper function. Anything matching test_* gets collected and run, so a helper needs a name outside that pattern.
- File matches test_*.py — discovered automatically, no registration needed
- Function matches test_* — collected and run as a test
- assert add(2, 2) == 5 — ordinary Python — no assertEqual needed
- Rewritten at collection time — failure shows: assert 4 == 5, + where 4 = add(2, 2)
Discovery naming rules
Together
Remember: pytest finds tests by name (test_*.py, test_* functions) — write plain assert statements, and pytest's rewriting shows exactly what did not match on failure.
See also: fixtures and scopes · marks and plugins

