Technologie

Automatyzacja testów: jak nie utonąć w kosztach utrzymania kodu testowego

Zautomatyzowanie każdego możliwego scenariusza nie oznacza lepszej jakości oprogramowania. Liczy się dobór testów według ryzyka, szybkości informacji zwrotnej i kosztu ich późniejszego utrzymania.

4 min czytania

Jak wybierać testy do automatyzacji? Praktyczne kryteria dla programistów
Jak wybierać testy do automatyzacji? Praktyczne kryteria dla programistów

Zespoły programistyczne, które stawiają na automatyzację testów, zyskują szybsze tempo pracy i większą pewność co do jakości kodu. Warto jednak pamiętać, że test to również kod - a każdy dodatkowy test zwiększa koszty jego utrzymania, poprawiania i dopasowywania do zmian w aplikacji.

Z tego powodu decyzja o automatyzacji nie powinna opierać się jedynie na tym, co da się technicznie zautomatyzować. Równie istotne są dwa inne czynniki: wartość informacji, jaką test dostarcza, oraz koszt jego utrzymania w kolejnych miesiącach.

Punkt wyjścia: ryzyko regresji i cena błędu

Do automatyzacji nie powinny trafiać przede wszystkim te funkcje, które najprościej pokryć testem. Priorytetem powinny być obszary, w których awaria wywoła największe konsekwencje dla użytkowników.

Takim kryterium najczęściej odpowiadają płatności, mechanizmy autoryzacji, zarządzanie uprawnieniami, billing oraz kontrakty API. Gdy w tych miejscach dochodzi do regresji, skutki odczuwają użytkownicy albo zatrzymuje się cały proces biznesowy firmy.

Podczas selekcji testów warto sprawdzić cztery elementy:

  • Wpływ regresji - jakie konsekwencje wywoła awaria danego fragmentu?
  • Prawdopodobieństwo błędu - jak często zmienia się dany kod i od ilu zależności jest uzależniony?
  • Częstotliwość testowania - czy dany scenariusz jest weryfikowany przy każdym wydaniu?
  • Koszt utrzymania - jakiego nakładu pracy będzie wymagać test w przyszłości?

Taka analiza pomaga odróżnić test faktycznie ograniczający ryzyko od testu, który jedynie zwiększa liczbowy wskaźnik pokrycia kodu.

Warto również przeliczyć koszty zespołu związane z automatyzacją, czyli policzyć osobno jej ROI - zwłaszcza w tych miejscach, gdzie manualna regresja jest powtarzana przy każdym wdrożeniu.

Poziom testu powinien odpowiadać skali problemu

Nawet krytyczna funkcjonalność nie musi być zabezpieczona rozbudowanym testem typu E2E. Duża część ryzyka daje się ograniczyć testami jednostkowymi i integracyjnymi - są one szybsze, bardziej stabilne i mniej kosztowne w utrzymaniu.

Dobrym przykładem jest proces obsługi płatności.

Zasady wyliczania kwoty można zweryfikować testami jednostkowymi. Komunikację z gatewayem płatniczym lepiej pokryć testami integracyjnymi. Testy E2E powinny zostać zarezerwowane dla kilku kluczowych scenariuszy obejmujących cały przebieg procesu.

Taki podział zmniejsza koszty utrzymania i przyspiesza cykl informacji zwrotnej. Nie ma potrzeby uruchamiania przeglądarki, bazy danych, kilku usług oraz zewnętrznego środowiska sandbox tylko po to, by sprawdzić proste reguły domenowe.

To ma szczególne znaczenie w kontekście CI/CD. Jak wskazuje metodyka DORA, jednym z fundamentów Continuous Delivery jest szybkie uzyskiwanie informacji o jakości oprogramowania i jego gotowości do wdrożenia.

Jeśli pełna sekwencja testów trwa czterdzieści minut, informacja zwrotna dociera zbyt późno. Sytuacja jest jeszcze gorsza, gdy testy regularnie blokują pipeline, choć w kodzie nie ma żadnego błędu.

Testy niestabilne osłabiają zaufanie do całej automatyzacji

Test, który zawodzi w niestabilny sposób, nie daje realnego poczucia bezpieczeństwa. Każde jego niepowodzenie wymaga ustalenia, czy problem tkwi w aplikacji, czy w samym teście.

Na początku programista analizuje logi i próbuje odtworzyć błąd. Po kilku fałszywych alarmach zaczyna traktować wyniki z nieufnością. Kolejnym etapem jest ponowne uruchamianie testu „na wszelki wypadek”. Gdy taka sytuacja trwa dłużej, zaufanie do całego zestawu testów spada.

W efekcie każdy błąd trzeba interpretować, zamiast od razu traktować go jako sygnał realnego problemu.

Klasycznym przypadkiem jest test E2E zależny od niestabilnej usługi zewnętrznej. Jeśli regularnie kończy się niepowodzeniem z przyczyn niezwiązanych z własnym kodem, lepszym rozwiązaniem bywa zastąpienie go testem integracyjnym z kontrolowanym mockiem - taki test daje bardziej wiarygodny sygnał przy niższym koszcie utrzymania.

Kiedy automatyzacja się nie opłaca

Nie każdy scenariusz warto automatyzować, nawet jeśli jest to technicznie możliwe.

Niski zwrot z inwestycji zwykle dotyczy funkcji zmieniających się bardzo często, krótkotrwałych eksperymentów, jednorazowych migracji oraz obszarów wymagających subiektywnej oceny.

Jeśli test E2E jest silnie powiązany ze szczegółami interfejsu, każda większa zmiana w UI może wymuszać jego przebudowę. Gdy dany scenariusz jest wykonywany rzadko, a jego ręczna weryfikacja zajmuje niewiele czasu, koszt automatyzacji może przewyższyć realną korzyść.

Liczy się jakość informacji zwrotnej, nie sam procent pokrycia

Wskaźnik pokrycia testami bywa użyteczny, ale nie mówi wprost, czy chronione są rzeczywiście najważniejsze obszary aplikacji.

Można mieć 90 procent pokrycia i wciąż nie zabezpieczać kluczowej ścieżki użytkownika. Można też mieć znacznie niższy wskaźnik, a jednocześnie otrzymywać szybki i stabilny sygnał o tym, czy dana zmiana jest gotowa do wdrożenia.

Najlepszym testem sprawdzającym jakość zestawu testów jest proste pytanie:

Czy kiedy wszystkie testy przechodzą, naprawdę ufasz, że możesz bezpiecznie wdrożyć zmianę?

Jeśli wszystkie testy przechodzą, a przed wdrożeniem i tak konieczne jest ręczne przeklikanie połowy aplikacji, oznacza to problem w doborze testów albo realne luki w pokryciu.

Jak podkreślają eksperci Pragmatic Coders, automatyzację warto rozpatrywać właśnie przez pryzmat ryzyka, jakości feedbacku i kosztu utrzymania.

Nie potrzebujesz testu dla każdego możliwego przypadku. Potrzebujesz takich testów, które szybko wykrywają regresje tam, gdzie ich koszt jest najwyższy, a przy tym pozostają wystarczająco stabilne, żeby zespół mógł im zaufać.

Pragmatic Coders

Źródło: Programista