Powrót do: Praktyczne wprowadzenie do testów automatycznych z Playwright
Bonus: Flaky tests – jak podejść do niestabilnych testów?
Flaky tests.
Temat, który spędza sen z powiek, gdy automatyzujemy testy.
W tym kursie, tak samo jak w realnym projekcie, projektujemy framework i musimy stawić czoła tego typu testom.
W tej lekcji pokażę Ci, czym są flaky tests, jak je rozpoznać, i podstawowe techniki postępowania. Wszystko – na podstawie rozwijanego wspólnie frameworka opartego o Playwright.
Prezentacja
Flaky tests – czym są?
Flaky tests (niestabilne testy) to testy, które – w prostych słowach – czasem przechodzą, a czasem nie, pomimo tego, że w aplikacji i w testach nie zostały wprowadzone żadne znaczące zmiany pomiędzy uruchomieniem testów.
Dla lepszego zobrazowania wyobraź sobie taki scenariusz:
-
Pierwsze uruchomienie
Test przechodzi – użytkownik poprawnie loguje się do systemu. -
Drugie uruchomienie (od razu po pierwszym)
Test nie przechodzi mimo tego samego scenariusza logowania, pojawia się błąd w testach, na przykład test nie może znaleźć przycisku “Zaloguj”. -
Trzecie uruchomienie (od razu po drugim)
Test znowu przechodzi – wszystko działa, jakby nic się wcześniej nie wydarzyło!
Dlaczego flaky testy są problematyczne?
- Podważają zaufanie do wyników testów
Gdy testy czasami przechodzą, a czasami nie, zespół przestaje traktować wyniki automatycznych testów jako wiarygodne źródło informacji o stanie aplikacji. Może to prowadzić do nieświadomego pomijania rzeczywistych błędów.
- Wydłużają czas debugowania
Znalezienie przyczyny problemu w przypadku flaky testów jest znacznie trudniejsze niż w przypadku testów, które konsekwentnie wskazują na błąd. Testerzy muszą analizować logi, środowisko uruchomieniowe i konfigurację, często wielokrotnie uruchamiając te same testy.
- Mogą prowadzić do ignorowania wyników testów
Zespół może zacząć ignorować zarówno niepowodzenia, jak i sukcesy w automatycznych testach, zakładając, że wynik nie ma związku z rzeczywistym stanem aplikacji. W efekcie prawdziwe błędy mogą pozostać niezauważone i trafić na produkcję.
- Wydłużają czas dostarczania oprogramowania
Gdy zespół musi regularnie radzić sobie z flaky testami, spowalnia to cały proces wytwarzania oprogramowania (w prostych słowach – tworzenia aplikacji). Dodatkowy czas jest poświęcany na weryfikację wyników i analizowanie problemów.
- Generują dodatkowe koszty
Dodatkowy czas poświęcony na analizę i uruchamianie testów to realny koszt, który łatwo można przeliczyć na pieniądze. A klienci nie lubią tracić pieniędzy…
- Powodują frustrację w zespole
Ciągłe problemy z niestabilnymi testami mogą prowadzić do spadku morale zespołu. Szczególnie gdy czas i wysiłek są regularnie marnowane na problemy związane z flaky testami (analiza, uruchamianie testów aby zreprodukować losowe błędy) zamiast na rzeczywistą wartość dla klienta i użytkowników.
Powodem mogą być błędy w aplikacji, problemy ze środowiskiem lub błędy w implementacji testów:
- test próbuje wchodzić w interakcję z elementem, zanim ten element załaduje się na stronienie, czyli niewłaściwe oczekiwanie na elementy lub dane (np. brak odpowiedniego
wait
) - środowisko jest niestabilne, np. sieć działa wolniej w danym momencie, co powoduje timeout lub z dostępnością serwerów
- test opiera się na dynamicznych danych, które mogą różnić się przy każdym uruchomieniu.
- w aplikacji występują błędy związane z wyścigiem – gdy dwie operacje wykonują się w tym samym czasie i raz jedna kończy się wcześniej a raz druga
Uruchamianie testów wiele razy i opcja repeat-each
Playwright oferuje opcję repeat-each.
Opcja repeat-each pozwala uruchamiać ten sam test wielokrotnie w jednej sesji. Służy do wykrywania niestabilności w testach (flaky tests) i pomaga sprawdzić, czy wynik danego testu jest powtarzalny.
Czyli czy kończy się powodzeniem przy wielu uruchomieniach.
Jak działa repeat-each?
- dla każdego testu Playwright uruchomi go określoną liczbę razy
- jeśli test przechodzi za każdym razem, oznacza to, że jest stabilny
- jeśli test nie przechodzi w niektórych powtórzeniach – to zostanie oznaczony jako flaky test, może to wskazywać na problem z testem, aplikacją lub środowiskiem
Kiedy używać repeat-each?
- Do sprawdzania stabilności testów
- Podczas debugowania niestabilnych testów (flaky tests)
- Przy testowaniu wprowadzonej zmiany, aby upewnić się, że nie wpływa ona na stabilność testów
- W symulacji testów na obciążonym środowisku, by sprawdzić ich zachowanie
Przykład zastosowania
Jeśli masz test, który czasami się nie udaje z powodu niestabilności aplikacji, możesz użyć repeat-each
, aby wielokrotnie go uruchomić i zobaczyć, czy problem występuje losowo.
Podsumowując, repeat-each można traktować jako narzędzie diagnostyczne do testowania stabilności, które umożliwia wielokrotne wykonywanie tych samych testów.
Polecenie do uruchomienia wszystkich testów, gdzie każdy z testów zostanie uruchomiony 10 razy:
npx playwright test --repeat-each=10
Opcja retries, czyli ponownie uruchomienie testów zakończonych niepowodzeniem
Opcja retries w Playwright pozwala na automatyczne ponowne uruchomienie testu, jeśli za pierwszym razem test zakończy się niepowodzeniem.
Jak działa retries?
- dla każdego testu Playwright uruchomi go określoną liczbę razy
- jeśli test przechodzi za każdym razem, oznacza to, że jest stabilny
- jeśli test nie przechodzi w niektórych powtórzeniach – to zostanie oznaczony jako flaky test, może to wskazywać na problem z testem, aplikacją lub środowiskiem
Kiedy korzystać z retries?
Jest to szczególnie przydatne, gdy testy:
- są wrażliwe na chwilowe błędy, na przykład problemy z siecią lub czasowe opóźnienia w ładowaniu strony
- polegają na zewnętrznych usługach, które mogą czasem działać niestabilnie (np. API firm trzecich)
- testują dynamiczne treści, które mogą zmieniać się w czasie rzeczywistym (np. dane w czasie rzeczywistym, jak kursy walut)
- mają zależności od środowiska testowego, które może nie być w pełni stabilne (np. problemy z infrastrukturą testową)
Zalety tego mechanizmu:
- stabilizacja testów – może być przydatne w środowiskach z niestabilnymi elementami.
- skrócenie czasu analizy błędów, bo niektóre błędy mogą być jednorazowe i nie wymagają natychmiastowej interwencji.
Każdy test, który dopiero przy powtórzeniu zakończył się powodzeniem, jest odpowiednio oznaczany w raportach (jako flaky test).
Dzięki temu podczas analizy wyników możemy łatwo odszukać takie testy a następnie zaplanować ich analizę.
Wady tego podejścia:
- ukrywanie problemów, bo wielokrotne ponowne uruchomienia mogą maskować rzeczywiste problemy w testach
- dłuższy czas uruchamiania, bo w przypadku częstych retry czas wykonania testów może się wydłużyć
Lepiej jest najpierw ustabilizować testy, a retry traktować jako ostateczność.
Również przed użyciem tej opcji powinieneś:
- dobrze przeanalizować występujący błąd
- zgłosić go w projekcie (aby zespół był tego świadomy)
Najlepsze praktyki:
- używaj retry w środowiskach, gdzie niestabilność jest znana i akceptowana
- staraj się minimalizować flaky testy poprzez debugowanie i wprowadzanie poprawek do testów i aplikacji
- analizuj działanie testów oraz aplikacji, aby zrozumieć przyczyny problemów i ocenić czy wykorzystać mechanizm retries
Jak korzystać z retries?
Opcja retry podczas uruchamiania testów:
npx playwright test --retries=3
Opcja retry w konfiguracji playwright.config.ts:
retries: process.env.CI ? 2 : 2,
Opcja retry dla konfiguracji testów (w kodzie):
test.describe.configure({ retries: 2 });
Podsumowanie
Opcja retries a repeat-each
- W odróżnieniu od opcji
retries
,repeat-each
nie kończy testów po pierwszym nieudanym przebiegu – każdy test jest uruchamiany określoną liczbę razy, niezależnie od wyniku. - Opcja ta jest szczególnie przydatna w środowiskach CI/CD do wykrywania potencjalnych problemów przed wdrożeniem.
Flaky tests w aplikacji Demo Bank
Poprawka w teście i cały kod
W teście można dodać inteligentne czekanie na pełne załadowanie się strony.
Służy do tego metoda:
await page.waitForLoadState("domcontentloaded");
Wywołanie jej spowoduje, że Playwright poczeka, aż cały dokument HTML sie załaduje zanim wykona kolejne operacje.
Zawartość pliku pulpit.spec.ts:
import { test, expect } from "@playwright/test"; test.describe("Pulpit tests", () => { test("quick payment with correct data", async ({ page }) => { await page.goto("https://demo-bank.vercel.app/"); await page.getByTestId("login-input").fill("testerLO"); await page.getByTestId("password-input").fill("password"); await page.getByTestId("login-button").click(); await page.waitForLoadState("domcontentloaded"); // wait for all DOM content loaded await page.locator("#widget_1_transfer_receiver").selectOption("2"); await page.locator("#widget_1_transfer_amount").fill("150"); await page.locator("#widget_1_transfer_title").fill("pizza"); await page.getByRole("button", { name: "wykonaj" }).click(); await page.getByTestId("close-button").click(); await expect(page.locator("#show_messages")).toHaveText( "Przelew wykonany! Chuck Demobankowy - 150,00PLN - pizza" ); }); });
Podstawowy algorytm postępowania
-
Potwierdzenie problemu
- Sprawdź, czy test faktycznie jest flaky (np. uruchamiając go wielokrotnie za pomocą opcji
--repeat-each=10
) - Przeanalizuj logi i historię testu w CI/CD
- Sprawdź, czy test faktycznie jest flaky (np. uruchamiając go wielokrotnie za pomocą opcji
-
Analiza z zespołem
- Przedyskutuj problem podczas spotkania zespołowego.
- Omów możliwe przyczyny flaky tests (kod testu, kod aplikacji, środowisko).
- Oceń koszty naprawy i zdecyduj, kiedy i jak podjąć działania naprawcze.
-
Tymczasowe rozwiązanie (jeśli aktualnie są inne priorytety)
- Dodaj opcję retries do konfiguracji danego testu lub przy komendzie do uruchamiania testów:
npx playwright test --retries=3
- Udokumentuj problem – stwórz notkę (task/issue w danym systemie, np. Jira), w której opiszesz całą dotychczasową analizę, aby wrócić do tego problemu później.
- Dodaj opcję retries do konfiguracji danego testu lub przy komendzie do uruchamiania testów:
-
Naprawa
- Popraw test, kod aplikacji lub dostosuj środowisko.
- Zoptymalizuj framework (np. timeouty, dynamiczne oczekiwania).
-
Weryfikacja
- Uruchom test wielokrotnie, aby upewnić się, że problem został rozwiązany.
- Obserwuj stabilność testów w CI/CD.
-
Prewencja
- Wprowadź monitorowanie flaky tests w CI/CD.
- Zaktualizuj dobre praktyki w dokumentacji zespołowej.
Podsumowanie
W tym momencie masz już podstawową wiedzę czym są flaky tests i wiesz jak je wykrywać
Poznałeś też prosty algorytm, kroki co zrobić, gdy odkryjesz takie testy w projekcie.
W dalszej części kursu i w części zaawansowanej, gdzie projektujemy profesjonalny framework, pokażemy Ci inne techniki jak analizować problemy i stabilizować testy.
Wszystko w oparciu o naszą praktyczną wiedzę o Playwright, którą pozyskaliśmy w wielu komercyjnych projektach 😉
Zewnętrzne linki i zasoby
- Oficjalna dokumentacja Playwright: https://playwright.dev/docs/test-retries
- Dwa słowa więcej o Flaky Tests
- Oficjalna dokumentacja Playwright: repeatEach w konfiguracji
- Oficjalna dokumentacja Playwright: repeat-each jako opcja przy uruchamianiu testów
Hejo,
chyba się litrówka trafiła w pierwszym slajdzie. Nie powinno być “raz kończą się błędem”? 🙂
Doskonałe oko testera!
Faktycznie jest tam literówka – na slajdach pod nagraniem już poprawiłem 😉
A nagranie wyrenderuje przy kolejnej okazji 😀
Dzięki wielkie za zgłoszenie!
Hej!
1. Powtórzyłem przypadek z nagrania i rzeczywiście dodanie “await page.waitForLoadState(“domcontentloaded”); ” wydaje się rozwiązywać problem w przypadku jednego testu
2. Jednak w pliku pulpit.spec.ts mam kod z lekcji L06 (formatowanie kodu z prettier), a tam są dwa testy. Uruchomiłem testy poleceniem “npx playwright test –repeat-each=100” i dostałem 3 flaky tests
3. W każdym z nich występuje znany problem “Received string: “Brak wiadomości”” Zastanawiam się dlaczego wystąpił ten przypadek mimo dodania metody “waitForLoadState” ? Może wykonałem test nieprawidłowo? Poniżej kod
Hej,
Świetne pytanie i sprawdzenie tego mechanizmu w boju! 😀
Faktycznie wprowadzenie opcji
await page.waitForLoadState("domcontentloaded");
stabilizuje testy, ale nadal nie w 100%. Tutaj też poprawnie zastosowałeś ten mechanizm do pozostałych testów.I taka sytuacja może też być w realnym projekcie.
Zatem kolejnymi krokami byłby powrót do przedstawionego algorytmu:
– sprawdzamy błąd – znowu dotyczy tego samego obszaru, wiec możliwe, że powodem jest coś innego niż skrypty lub potrzebne jest jakies inne zabezpieczenie w testach, aby upewnić się, że strona jest gotowa do działania
– moze byc też tak, że jest to jakis ukryty bug w aplikacji.
Uruchomiłeś
npx playwright test –repeat-each=100
al na wszystkich testach (zakładam też ze na domyślnym ustawieniu 4 workerów) – może jest jakiś problem z wydajnością aplikacji?– błąd dotyczy tylko wiadomości bo wyliczenia cały czas są poprawne
– i co ważne – cały czas nie jesteśmy w stanie manualnie tego zreprodukować
Z tego wynika, że może to nie być trywialny problem i może wymagac dodatkowego czasu na analizę – najlepiej wykonaną z udziałem developera, aby poznać mechanizmy w aplikacji.
Uwzględniając powyższe – może się okazać, ze aktualnie najlepsze rozwiązanie to będzie dodac opcję retry do tych testów i założyć, że w przyszłości wróci się do analizy tego problemu 🙂
Z doświadczenia powiem, że czasem takie rozwiązania się stosuje i często rozwiązanie przychodzi w nieoczywistym momencie:
– gdy wykonywana jest jakaś refaktoryzacja kodu aplikacji
– gdy naprawiany jest jakiś inny błąd
– gdy podbijane są biblioteki z których korzystamy w projekcie
A dzięki raportom i logom, możemy monitorować jakie testy są flaky i jakie błędy występują 🙂
Ten przypadek świetnie obrazuje niekończącą się walkę z flaky tests 😉