Skip to main content

Introduction to pytest (Part 1): Basic tests and markers

If unittest is the standard library stalwart, pytest is the community’s daily driver: plain functions, expressive assert introspection, and plugin hooks that integrate with IDEs and CI.

pip install pytest

📚 Prerequisites


🎯 What you'll learn

  • Author tests as test_* functions with simple assert.
  • Run subsets of a suite by path, node id, or keyword.
  • Attach markers (metadata “attributes”) for filtering slow or network tests.

First pytest module

# test_add.py
from math_utils import add


def test_add_basic():
assert add(2, 3) == 5


def test_add_identity():
assert add(0, 7) == 7
pytest -q

Failures print intermediate sub-expressions automatically—no need for self.assertEqual boilerplate.


Markers as test attributes

import pytest


@pytest.mark.slow
def test_heavy_import():
import expensive_optional_dep # noqa: F401

Run everything except slow tests:

pytest -m "not slow"

Register custom markers in pytest.ini to avoid typos:

[pytest]
markers =
slow: long-running integration scenario

Targeted runs

pytest tests/test_api.py
pytest tests/test_api.py::test_health
pytest -k "health and not slow"

💡 Key takeaways

  • Pytest’s ergonomics encourage writing more tests—lower friction means higher coverage naturally.

➡️ Next steps

Layer fixtures, parametrization, and ASGI clients in pytest Part 2.