Strategia testów¶
Aster stosuje pięciowarstwową strategię testów inspirowaną klasyczną piramidą testową — najwięcej testów na dole (szybkie, tanie), najmniej na górze (wolne, drogie, ale realistyczne).
graph TD
sec["🛡️ Bezpieczeństwo<br/>bandit + pip-audit + Django check"]
perf["⚡ Wydajność<br/>locust"]
a11y["♿ Dostępność<br/>pa11y"]
e2e["🌐 E2E (Playwright)<br/>3 scenariusze"]
integ["🔌 Integracyjne (pytest + Django Client)"]
unit["🧪 Jednostkowe (pytest)"]
unit --> integ --> e2e --> perf
integ --> a11y
integ --> sec
style unit fill:#dff5e1
style integ fill:#dff5e1
style e2e fill:#fff5d6
style perf fill:#fde7e9
style a11y fill:#dde7ff
style sec fill:#dde7ff
Warstwy¶
Testy jednostkowe¶
- Definicja: sprawdzają jeden moduł / jedną funkcję w izolacji od bazy i sieci.
- Narzędzie:
pytest. - Lokalizacja:
accounts/tests.py,core/tests.py,movies/tests.py.
Testy integracyjne¶
- Definicja: weryfikują współpracę widoków, formularzy, ORM i bazy danych.
- Narzędzie:
pytest-django+ DjangoClient(HTTP-jak w-procesie). - Lokalizacja: te same pliki co jednostkowe — pytest-django wybiera markery i fixtury.
Testy end-to-end (E2E)¶
- Definicja: symulacja prawdziwego użytkownika w przeglądarce; sprawdza ścieżki happy-path z pełnym frontendem (HTML + JS + Bootstrap modal).
- Narzędzie:
pytest-playwright+ Chromium headless. - Lokalizacja:
tests/e2e/. - Scenariusze (mapa 1:1 ze ścieżkami użytkownika):
- Rejestracja → e-mail → aktywacja → logowanie (
test_register_login.py) - Przeglądanie → ocena 4★ → komentarz (
test_browse_rate_comment.py) - Watchlist → watched (
test_watchlist.py)
- Rejestracja → e-mail → aktywacja → logowanie (
- Uruchamianie:
DJANGO_ALLOW_ASYNC_UNSAFE=true uv run pytest tests/e2e -m e2e - CI:
.github/workflows/e2e.yml— push domaini PR domain.
Testy wydajnościowe¶
- Definicja: ocena czasów odpowiedzi i przepustowości pod obciążeniem.
- Narzędzie:
locust. - Lokalizacja:
tests/perf/locustfile.py. - Trzy ważone profile użytkowników:
AnonymousBrowser(waga 70%) —/,/movies/, losowy/movies/<id>/LoggedInBrowser(waga 25%) — login + browse + profilSearcher(waga 5%) —/movies/?q=<query>
- Cele: p95 < 500 ms, < 1% błędów, 50 użytkowników jednocześnie przez 5 min.
- Cel uruchamiania: lokalny gunicorn (1 worker, jak na Render).
- CI: brak — uruchamiane ręcznie (CI runners są zbyt zmienne dla wiarygodnych liczb perfowych).
Testy bezpieczeństwa¶
Trzy automatyczne skanery uruchamiane na każdym PR:
| Narzędzie | Co sprawdza | Próg blokujący |
|---|---|---|
bandit -r |
wzorce niebezpiecznego kodu Python (eval, hardcoded passwords, weak crypto) | severity ≥ medium |
pip-audit |
znane CVE w zależnościach z PyPI Advisory DB | dowolne znalezisko |
manage.py check --deploy --fail-level WARNING |
konfiguracja produkcyjna Django (HSTS, secure cookies, SSL redirect…) | dowolne ostrzeżenie |
Testy dostępności¶
- Narzędzie:
pa11y(HTML_CodeSniffer, standard WCAG2AA). - Strony pokryte:
/auth/login/,/auth/register/,/movies/,/movies/<id>/. - Uruchamianie: ręcznie / przed wydaniem (procedura w Raportach).
Polityka jakości¶
- Każdy PR musi przechodzić workflowy
CI(lint + type + unit) iSecurity. - PR do
maindodatkowo przechodząE2E. mainautomatycznie buduje i deployuje dokumentację (Docsworkflow).- Statyczna analiza uruchamiana lokalnie przez pre-commit (
ruff,ty). - Pokrycie kodu raportowane w PR (
pytest --cov); brak twardego progu — tracimy go celowo świadomie, bo wymuszenie 100% prowadzi do bezsensownych testów.