Installation and structure
pip install pytest
Tests go in a separate folder alongside the code:
myproject/
app/
utils.py
tests/
test_utils.py
The naming rule: files start with "test_", and so do the functions inside. Otherwise they simply won't be found.
A first test
from app.utils import shorten
def test_returns_text_unchanged_when_short():
assert shorten("Hello", 10) == "Hello"
Run from the project root:
pytest
Or verbosely, showing each test:
pytest -v
Checking exceptions
Often you need to confirm a function objects to bad data:
import pytest
def test_raises_on_negative_limit():
with pytest.raises(ValueError):
shorten("text", -1)
One test, many cases
Instead of five nearly identical tests, one with parameters:
@pytest.mark.parametrize(
"text,limit,expected",
[
("hello", 10, "hello"),
("a long piece", 5, "a lon…"),
("", 5, ""),
],
)
def test_shorten(text, limit, expected):
assert shorten(text, limit) == expected
Each row becomes a separate test. When one case fails, you see exactly which.
Preparing data
When a test needs something set up in advance, that goes into a fixture:
@pytest.fixture
def sample_notes():
return [
{"id": 1, "title": "First"},
{"id": 2, "title": "Second"},
]
def test_finds_by_id(sample_notes):
assert find_note(sample_notes, 2)["title"] == "Second"
The fixture runs before each test that asks for it, sparing you from copying setup into every test.
Testing a service
If you have a web service, you can test it without starting a real server — frameworks provide a test client:
def test_notes_endpoint_returns_list(client):
response = client.get("/notes")
assert response.status_code == 200
assert isinstance(response.json(), list)
Check not only the happy path but the error codes: what comes back for a missing record and for invalid data.
Useful flags
pytest tests/test_utils.py one file only
pytest -k "shorten" only tests with this word in the name
pytest -x stop at the first failure
pytest --lf rerun only last time's failures
The last two save a lot of time while fixing things.
When a test fails
Read the whole output. It shows expected against actual — usually the cause is immediately visible.
Don't edit the test to make it pass. First establish who is wrong: the code or the test. Bending a test to fit broken code is the most harmful habit there is.
Isolate it. Run the failing test alone. Passing alone but failing together means the tests influence each other through shared state. That's a separate and common problem.
What makes tests useful
Independence: every test should work by itself and in any order. Tests that depend on execution order eventually start failing at random, and then nobody trusts them.
Хватит читать — пора делать
На CohortX можно найти команду под пет-проект и получить тот самый опыт, о котором спрашивают на собеседовании.
Похожие статьи
- Первые тесты на Python: практическое введениеКак установить, где размещать файлы, как писать проверки и подготовку данных, как запускать и что делать с падениями.
- FastAPI: your first service in an eveningWhat a service for programs is, how to write your first one in an evening, and why automatic documentation saves time.
- FastAPI: первый сервис за вечерЧто такое сервис для программ, как написать первый за вечер и почему автоматическая документация экономит время.