Unit Testing with pytest
Setup
pip install pytest
pytest finds files named test_*.py and functions named test_*.
A first test
app/services/pricing.py:
from decimal import Decimal, ROUND_HALF_UP
ZERO_DECIMAL = {"jpy", "krw"}
def to_minor_units(amount, currency):
value = Decimal(str(amount))
if currency.lower() in ZERO_DECIMAL:
return int(value.quantize(Decimal("1"), rounding=ROUND_HALF_UP))
return int((value * 100).quantize(Decimal("1"), rounding=ROUND_HALF_UP))
tests/test_pricing.py:
from app.services.pricing import to_minor_units
def test_usd_rounds_instead_of_truncating():
assert to_minor_units(19.99, "usd") == 1999
def test_jpy_has_no_minor_units():
assert to_minor_units(100, "JPY") == 100
pytest -q
pytest tests/test_pricing.py -k jpy -v # run matching tests, verbose
pytest -x # stop at first failure
pytest --lf # rerun only last failures
pytest uses plain assert and shows exactly which values differed when it fails.
Arrange, Act, Assert
def test_completing_a_module_awards_points_once():
# Arrange
user = make_user(points=0)
# Act
complete_module(user, module_id=7)
complete_module(user, module_id=7)
# Assert
assert user.points == 10
Three clear sections make tests easy to read and debug.
Many cases with parametrize
import pytest
@pytest.mark.parametrize("amount, currency, expected", [
(0.01, "usd", 1),
(10, "eur", 1000),
(19.995, "usd", 2000),
(500, "jpy", 500),
])
def test_to_minor_units(amount, currency, expected):
assert to_minor_units(amount, currency) == expected
Each row runs as its own test with its own result.
Testing errors
def test_rejects_negative_amounts():
with pytest.raises(ValueError, match="negative"):
charge(-5)
Test edge cases deliberately
For any function, ask: empty input? None? zero? negative? very large? unicode? duplicates? boundaries (exactly at a limit, one above, one below)? Most bugs live at the edges.
Exercise
Write parametrized tests for a slugify(text) function covering normal titles, punctuation, unicode, empty strings and maximum length.
Ihr Fortschritt wird nur in diesem Browser gespeichert.
Zur Prüfung einreichen (10 Punkte)