Parametrize
When several tests differ only in their data, write the test once and hand pytest the cases. Each case runs as its own test with its own result, so one broken case does not hide the others, and the report names the case that failed, such as test_upper[ab-AB].
import pytest
@pytest.mark.parametrize("text, want", [
("ab", "AB"),
("", ""),
pytest.param("ß", "SS", id="sharp-s"),
])
def test_upper(text, want):
assert text.upper() == want, text
# Each case becomes one call:
test_upper("ab", "AB")
test_upper("ß", "SS")
print("cases pass")Picking cases
Choose one case for each rule the code follows, and cases on both sides of every exception to a rule. Ask of each case which bug only it would catch. If the answer is none, it is not earning its line.
pytest.param(..., id="name") gives a case a readable name in the report, and stacking two parametrize decorators runs every combination of their values.
Your task
is_leap(year) is written for you. Write one test, test_is_leap(year, want), parametrized with at least four cases, so that it fails if any leap-year rule is lost: every fourth year, except centuries, except every fourth century.
The explanation opens here once every check passes.