-
Notifications
You must be signed in to change notification settings - Fork 0
TECH TALK 1 WPROWADZENIE DO TESTÓW
"Mój kod działa, sprawdziłem ręcznie" - Anonimowy Programista
Testy zapewniają nam, m. in.:
- powtarzalność wyników (podczas ręcznego wykonywania testu, człowiek może łatwo popełnić błąd)
- oszczędność czasu - raz napisane testy będą służyć wciąż i wciąż
- dobrze napisane testy mogą być doskonałą dokumentacją dla kodu, która zawsze będzie aktualna (jeśli nie - testy nie będą przechodzić)
// Dyskusja
-
Testy jednostkowe (ang. unit tests) - u nas: praktycznie brak :( WIĘCEJ: Wprowadzenie Jeffa Knuppa
-
Testy komponentowe (ang. component unit tests)(w Pythonie ciężko o dobry przykład)
-
Testy kontraktowe (ang. contract tests), np. pact WIĘCEJ: Pact Consumer Driven Contracts
-
Testy integracyjne (ang. integration tests) - u nas: wiekszość (django testy z odpaleniem DB i stawianiem lokalnie serwera)
-
Testy systemowe- (ang. End To End Test lub E2E tests) u nas: kilka testow do odpalania na klastrze (api-integration*.py)
Podstawą piramidy powinny być testy jednostkowe - ze względu na szybkość, precyzję, łatwość przygotowania/napisania. Następne powinny być testy integracyjne, które sprawdzą kooperację pomiędzy komponentami, np. przepływ (ang. flow) lub zgodność interfejsów. Na samym szczycie powinny być testy E2E. Są one "najcięższe" i najbardziej kosztowne w napisaniu/utrzymaniu. Można ich używać jako testów akceptacyjnych (testów mających na celu potwierdzenie, że w kodzie "nie ma już błędów", np. demo dla klienta).
WIĘCEJ: Gradacja i rodzaje testów wg inżynierów Google
Powinny mieć właściwości FIRST
- Fast - szybkie: kilkaset / kilka tysięcy testów na sekundę
- Isolates - izolacja: przyczyna nieprzechodzenia testu jest oczywista
- Repeatable - powtarzalność: dają ten sam rezultat, niezależnie od kolejności, czasu (pory), faktu puszczania w izolacji bądź w zestawie (tzw. test suit - "garnitur", zestaw, klasa testów)
- Self-validating - samosprawdzające: nie potrzeba eksperta z domeną wiedzą, żeby określić czy test przeszedł czy nie; dają jednoznaczną odpowiedź - tak/nie
- Timely - o czasie: są dostępne (mogą być użyte do sprawdzenia kodu) wystarczająco wcześnie (w idealnym świecie - przed powstaniem kodu produkcyjnego)
WIĘCEJ: FIRST - właściwości Unit Testów
funkcja: validate_report_computed_task_time_window
(w concent_api/core/validation.py
)
test: test_core_views.test_send_should_return_http_400_if_task_to_compute_younger_than_report_computed
Co zyskujemy preferując testy jednostkowe (nad testy integracyjne) do testowania małych kawałków kodu (unit-ów)?
- szybkość
- łatwiejszy przygotowanie (setup)
- dokładność (w przypadku nieprzechodzia testu łatwiej zidentyfikować przyczynę - błąd w kodzie)
Napisać test jednostkowy dla funkcji i porównać czas trwania z testem integracyjnym django (python manage.py test core.tests.test_core_views.CoreViewSendTest.test_send_should_return_http_400_if_task_to_compute_younger_than_report_computed
):
def validate_report_computed_task_time_window(report_computed_task):
assert isinstance(report_computed_task, message.ReportComputedTask)
if report_computed_task.timestamp < report_computed_task.task_to_compute.timestamp:
raise Http400("ReportComputedTask timestamp is older then nested TaskToCompute.")
PODPOWIEDŹ: Można użyć self.assertRaises()
z unittest
albo pytest.raises()