encyklopedia.space

pytest

pytest – otwartoźródłowy framework do testowania jednostkowego i funkcjonalnego w języku Python. Zaprojektowany z myślą o prostocie zapisu testów oraz rozbudowanej możliwości rozszerzania poprzez wtyczki. Dzięki intuicyjnemu podejściu i bogatemu zestawowi funkcji stał się jednym z najpopularniejszych narzędzi testowych w ekosystemie Pythona.

Historia

Projekt powstał w 2003 roku jako py.test, autorstwa Holgera Krekela. Pierwsza publiczna wersja zyskała uznanie dzięki minimalistycznemu podejściu do definiowania testów. Od 2007 roku rozwijany jest intensywnie przez społeczność open source, a od 2010 przyjęto nazwę pytest, wprowadzając liczne ulepszenia architektury i API. Projekt jest licencjonowany na zasadach MIT License.

Kluczowe cechy

  • Prosta konwencja nazewnictwa – testy są wykrywane automatycznie po nazwach zaczynających się od test_ lub kończących się na _test.
  • Wbudowane asercje języka Python, które nie wymagają oddzielnych metod assertEqual itp.
  • Wsparcie dla fixture’ów – pozwalają definiować wspólne przygotowanie i sprzątanie środowiska testowego.
  • Parametryzacja testów umożliwiająca uruchamianie jednej funkcji testowej z różnymi danymi wejściowymi.
  • Rozszerzalność poprzez wtyczki – np. pytest-cov (pokrycie kodu), pytest-xdist (równoległe wykonywanie testów), pytest-mock (mockowanie).
  • Integracja z innymi frameworkami testowymi, m.in. unittest, nose.
  • Bogate raportowanie – wyjścia w formacie tekstowym, HTML, JUnit XML i inne.

Podstawowe elementy

Testy

Testy w pytest definiuje się jako zwykłe funkcje lub metody klas, które nie przyjmują argumentów (poza fixture’ami). Przykład najprostszego testu:

def test_sum():
    assert sum([1, 2, 3]) == 6

Fixture’y

Fixture to specjalna funkcja oznaczona dekoratorem @pytest.fixture, której zadaniem jest przygotowanie środowiska testowego i opcjonalne sprzątanie po teście. Fixture’y mogą być współdzielone pomiędzy wieloma testami:

@pytest.fixture
def sample_data():
    return [1, 2, 3]

def test_average(sample_data):
    assert sum(sample_data) / len(sample_data) == 2

Parametryzacja

Dzięki dekoratorowi @pytest.mark.parametrize można uruchamiać ten sam test z różnymi zestawami danych:

@pytest.mark.parametrize("a,b,expected", [
    (1, 2, 3),
    (5, 7, 12),
    (0, 0, 0)
])
def test_addition(a, b, expected):
    assert a + b == expected

Uruchamianie testów

Podstawowe polecenie uruchamiające wszystkie testy w projekcie to:

pytest

Można dodać różne opcje, np.:

  • -v – tryb szczegółowy (verbose).
  • -k "nazwa" – uruchamianie testów pasujących do podanego wzorca.
  • --maxfail=3 – zatrzymanie po trzech niepowodzeniach.
  • --html=report.html – generowanie raportu w formacie HTML.

Rozszerzenia i wtyczki

Ekosystem pytest obejmuje setki wtyczek dostępnych w PyPI. Najczęściej używane:

Zastosowania

Framework jest wykorzystywany zarówno w małych projektach open source, jak i w dużych systemach komercyjnych. Dzięki elastyczności i możliwości integracji z CI/CD (np. Jenkins, GitHub Actions, GitLab CI) pytest stał się standardem w praktykach DevOps i ciągłej integracji.

Porównanie z innymi frameworkami

Cecha pytest unittest nose
Składnia asercji Wbudowane assert Metody assert* Wbudowane assert
Fixture’y Zaawansowane, z zakresem (function, module, session) SetUp/TearDown w klasach SetUp/TearDown, ograniczone
Parametryzacja Wbudowana (@pytest.mark.parametrize) Brak natywnej Wtyczki
Wtyczki Setki, aktywna społeczność Ograniczone Obecne, ale mniej aktywne

Przykładowy projekt

Poniżej przedstawiono prostą strukturę katalogów w projekcie wykorzystującym pytest:

my_project/
│
├─ src/
│   └─ calculator.py
│
├─ tests/
│   ├─ __init__.py
│   └─ test_calculator.py
└─ pyproject.toml   # opcjonalna konfiguracja pytest

W pliku test_calculator.py mogą znajdować się testy takie jak:

import pytest
from src.calculator import add, divide

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

@pytest.mark.parametrize("numerator,denominator,expected", [
    (10, 2, 5),
    (9, 3, 3),
    (5, 2, 2.5)
])
def test_divide(numerator, denominator, expected):
    assert divide(numerator, denominator) == expected

Konfiguracja

Ustawienia domyślne można nadpisać w pliku pytest.ini, tox.ini lub pyproject.toml. Przykładowa sekcja w pytest.ini:

[pytest]
addopts = -v --cov=src --html=report.html
testpaths = tests
python_files = test_*.py

Wspólnota i dalszy rozwój

Projekt jest rozwijany w otwartym modelu współpracy na platformie GitHub. Społeczność organizuje regularne spotkania (tzw. pytest-dev meetups) oraz utrzymuje listę planowanych funkcji w Roadmap. Dokumentacja dostępna jest w formie Read the Docs i jest stale aktualizowana.

Bibliografia

  • Oficjalna dokumentacja pytest – Documentation
  • Historia projektu – wpisy na GitHub repozytorium
  • Poradniki i case studies – sekcja Tutoriale w encyklopedii