Utrzymanie testów automatycznych w projektach, gdzie nie ma na to zbyt wiele czasu.

Dlaczego w ogóle mówimy o utrzymaniu?

Jeszcze kilka lat temu automatyzacja testów mogła wydawać się dosyć egzotycznym tematem i tak naprawdę nie wszystkie organizacje były na nie gotowe. Z czasem tak zwane seleniumy zaczęły zajmować dosyć znaczący sektor testów i w tym momencie chyba nikogo nie dziwi, że QA w firmie dąży do tego, by większość swojej regresji zautomatyzować. Czy faktycznie samo zapewnienie automatyzacji przynosi wymierne korzyści?

Chciałoby się powiedzieć, że odnieśliśmy sukces kiedy w organizacji namówiliśmy opornych do tego, by jednak zacząć pisać testy automatyczne. Ale dopiero po obyciu się z nimi w projektach zaczynamy zauważać pewną bardzo istotną sprawę. O ile w kontekście tworzenia software’u taki termin jak maintenance (ang. utrzymanie) jest dla nas dość oczywisty, o tyle przy automatach, zwłaszcza w niedoświadczonym zespole Quality Assurance, nie jest to już takie hop siup.

Wydawać by się mogło, że skoro zautomatyzowaliśmy pewien set testów i włączyliśmy go do regresji, a nawet zabezpieczyliśmy się procedurą mówiącą o tym, że każda zmiana w kodzie, wpływająca na działanie danej funkcjonalności powinna zakładać dodatkowy czas QA na poprawienie lub napisanie nowego automatu, to nie powinno wydarzyć się nic złego. Nasze automaty, skoro aplikacja testowana hipotetycznie się nie zmienia, powinny działać cały czas i dawać nam tą samą pewność, co do swojej rzetelności i wyników. Czym są przecież testy, którym nie ufamy, prawda?

No właśnie. Kwestia nie jest taka oczywista jak by się to mogło wydawać, bo nie pracujemy w książkowych i laboratoryjnych warunkach. Coby daleko nie szukać, rzucę kilka przykładów, dlaczego maintenance sam w sobie jest istotny, również w oderwaniu od zmian w kodzie:

  1. Infrastruktura. Testy i aplikacje są uruchamiane na konkretnych zasobach, a te mogą przecież się zmienić – ktoś w IT mógł podbić wersję oprogramowania, mógł dołożyć inny procesor i tak dalej. To mogło wpłynąć na działanie apki czy samych testów (np. testy zaczęły działać wolniej, co wypukliło pewne problemy aplikacji, lub aplikacja zaczęła pracować szybciej i nasze, jak do tej pory myśleliśmy, inteligentne waity nie do końca działają tak jakbyśmy chcieli).
  2. Niechciane zmiany w aplikacji. Nie wszystkie zmiany w działaniu aplikacji są pożądane. Czasami jedna zmiana, pozornie nieingerująca w inne moduły, zmienia duuuużo więcej, niż powinna. Co za tym idzie, nasze testy nagle z niewiadomych przyczyn zaczynają się wysypywać.
  3. Braki w komunikacji. Podobnie jak punkt wyżej, ale powiedzmy, że tym razem chodzi o chcianą zmianę w funkcjonalności. Niestety, ktoś zapomniał dopilnować procedury i nie zostaliśmy o tym na czas poinformowani. A roboty na następny sprint mamy całą masę. Efekt? Testy zaczynają się wywalać.
  4. Odporność aplikacji na testy (i/lub dane). Z czasem nasze testy mogą po prostu przestać spełniać swoje założenia, czy to w wyniku słynnego uodpornienia na testy, czy to ze względu na sumę zmian w pozostałych sektorach aplikacji.

Przykładów można podawać jeszcze więcej, ale sendo leży w tym stwierdzeniu: testy muszą być utrzymywane, żeby spełniały swoje założenia i były faktyczną pomocą dla QA (już abstrahując od tego, dla kogo są testy automatyczne, bo na ten temat też na pewno jeszcze napiszę – znowu, to nie takie proste 🙂 ).

Testy muszą być utrzymywane, żeby spełniały swoje założenia i były pomocne dla zespołu.

Kuba, Po szklanie i na testowanie

Sytuacja projektowa i brak czasu na utrzymanie testów

Ok, usystematyzowaliśmy potrzebę utrzymania testów, a teraz przedstawmy hipotetyczną sytuację: pracujemy w projekcie, który jest w fazie rozwojowej i faktycznie dużo rzeczy się zmienia, natomiast aplikacja ma na tyle ważne funkcjonalności (i ich działanie jest, powiedzmy, powtarzalne), że koniecznie chcemy mieć zautomatyzowaną regresję, ale żeby nie było za łatwo, niektórych zmiennych w projekcie nie mamy jak zastąpić (np. dużo integracji 3rd party, których nie możemy – z jakichś przyczyn – zamockować). Podnosząc stopień trudności już po raz ostatni, wyobraźmy sobie, że decydenci o wprowadzeniu testów automatycznych koniecznie chcieli mieć wdrożone Selenium, czy inne testy UI – dokładamy sobie trochę niestabilności, które nie są takie trywialne. A testerów w tym projekcie jest tylko dwóch, którzy pozornie są obładowani po same kokardy.

Jesteśmy więc w miejscu, w którym wiemy, że musimy utrzymywać testy; wiemy, że nasza aplikacja nie jest idealnym środowiskiem do długiego utrzymania testów bez ingerencji, ale wiemy też, że nie mamy wystarczająco czasu na to, by móc dołożyć zadanie pod tytułem utrzymanie testów.

Jak poradzić sobie z utrzymaniem testów w takiej sytuacji?

Z każdej sytuacji jest jakieś wyjście. Nie zawsze spełnia nasze oczekiwania i potrzeby w pełni, ale pamiętajmy – lepszy rydz, niż nic. Wiem, że to frazes, ale często w życiu to się sprawdza. Lepiej mieć dom 50m2, niż nie mieć gdzie mieszkać, bo nie stać nas na mieszkanie 100m2, prawda?

Razem z Pawłem zastanowiliśmy się, co moglibyśmy zrobić w takiej sytuacji i zebraliśmy listę kilku grubych punktów, które potencjalnie mogą Wam pomóc. Każdy projekt i zespół jest nieco inny, więc nie gwarantuję, że te pomysły jeden do jednego mogą być użyte u Was, ale prawdopodobnie z mniejszą bądź większą modyfikacją powinny Was przybliżyć do celu, jakim jest wygospodarowanie czasu na to, by jednak maintenance testów był możliwy.

Wybór testów automatycznych, które są kluczowe

Jednym z większych problemów podczas pisania testów automatycznych jest brak priorytetyzacji i selekcji testów regresji. Co to znaczy? Zbyt często próbujemy automatyzować wszystko – no dobra, wszystko to bardzo duże słowo, ale ilość zautomatyzowanych przypadków testowych bardzo często potrafi być zbyt wielka. Z jednej strony to dobrze, że automatyzujemy bardzo szeroki zakres funkcjonalności, ale wszystko się rozbija o to, czym i jak automatyzujemy. Przykładowo, im więcej testów UI, tym większa doza prawdopodobieństwa natrafienia na flaky testy. Inna kwestia to zbyt wiele danych testowych sprawdzających to samo zachowanie (tutaj często się kłania brak stosowania klas równoważności w praktyce testowania).

Dopóki wszystkie testy działają to pół biedy. Gorzej, gdy zaczynają się pojawiać pierwsze faile, a tam coraz więcej czerwonych kafelków i raporty zaczynają wyglądać coraz gorzej. Im więcej będzie czerwonych wyników, tym bardziej tracimy zaufanie do powstałych wcześniej testów automatycznych. Nie o to nam przecież chodzi, bo po jakimś czasie spoglądać na raporty z myślą „aaaaa, no ta, to się już wywalało, w sumie te 50 faili więcej już nie robi wrażenia”. Brzmi absurdalnie, nie?

Dlatego powinniśmy skupiać się na tym, by automatyzować naprawdę to, co kluczowe i przynosi nam wartość – ograniczmy zakres automatyzowanych przypadków, a zyskamy już w kilku punktach:

  1. Mniej czasu poświęcimy na automatyzację funkcjonalności samej w sobie (więcej czasu na inne aktywności)
  2. Mniej czasu musimy poświęcić na zmiany w tych testach, bo jest ich po prostu mniej

Dzięki takiemu podejściu możemy naprawdę sporo zyskać w trakcie trwania projektu. W chwili, gdy nie mamy czasu na bieżący maintenance, powinniśmy tę zasadę wprowadzać od teraz, czyli każdy kolejny feature traktowany jest właśnie takim sposobem. Kolejnym krokiem w takim podejściu byłoby wyłączenie testów, które i tak w tym momencie failują (co za tym idzie, nie będziemy poświęcać czasu na codzienne analizowanie tych samych przyczyn błędów, bo czasu na poprawę i tak nie mamy – dzięki temu te paręnaście lub kilkadziesiąt minut dziennie pojawia się w naszych kalendarzach) i skupienie się na włączeniu mniejszego, ale już poprawionego zakresu testów.

Analiza procesu i odjęcie niepotrzebnych czynności

Im dłużej pracujemy w jednym miejscu, tym trudniej złapać nam perspektywę. Warto regularnie oceniać swoje procesy, by wyłapywać w nich luki i uchybienia. Może masz w procesie testowym powtarzanie tych samych czynności na kilku środowiskach, albo testujesz regresję manualnie w zbyt szerokim zakresie, co realnie nie przekłada się wcale na lepszy biznes? Może poświęcasz zbyt dużo uwagi na feature’y, które z punktu widzenia biznesowego nie są aż tak ważne?

Jeśli pracujesz w zespole jako jedyny QA, poproś biznes, programistów czy innego kolegę o to, by być na chwilę Twoją kaczką i opowiedz im o swoim procesie. Może bardziej doświadczeni pokażą Ci, gdzie możesz zaoszczędzić kilka procent swojego czasu. A co z nim zrobić, to przecież już wiesz :).

Przesunięcie testów na inną warstwę

Pisząc nowe testy warto się zastanowić, czy na pewno powinny być zautomatyzowane tak bardzo na prawo. Left shift testing jest jedną z wiodących praktyk ostatnich miesięcy i warto o tym myśleć. Zadaj sobie pytanie, czy na pewno musisz uruchamiać UI, by przetestować ten kawałek aplikacji? Czy na pewno tutaj musisz używać pełnej integracji, czy może już na warstwie niżej udałoby się zautomatyzować te przypadki?

Im bardziej na lewo (czyt. im wcześniej testy będą uruchamiane, przez kolejnymi integracjami i podpinaniem frontendu), tym tańsze będzie analizowanie testów i poprawianie, czy – o, i teraz użyjemy tego słowa – utrzymanie. Nawet jeśli coś się zacznie kaszanić, im bardziej w lewo tym taniej i szybciej je ogarniemy. Pamiętajcie o tym.

Krótsze testy!

Nie jest nowością fakt, że zbyt długie testy, zwłaszcza na warstwie UI z pełną integracją end to end, potrafią same w sobie być bardzo niestabilne. Każdy kto słyszał o flaky testach pewnie wie o czym teraz mówię. Zdarzyło Wam się poprawiać wielokrotnie jeden test, mimo, że w aplikacji nic się w tym czasie nie zmieniało? Walka z flaky testami potrafi być bardzo wyniszczająca i męcząca. Co za tym idzie, droga i często nieopłacalna.

W takich sytuacjach warto myśleć o stosowaniu znacznie krótszych testów, które skupią się na mniejszej ilości kroków. Może więcej możesz ustawić przed samym testem za pomocą strzału do bazy danych, albo chociaż lepszego skorzystania z API? Może Twój test zawiera tak naprawdę kilka istotnych asercji, które spokojnie mogłyby być osobnymi testami?

Przemyśl to, czy na pewno Twoje testy nie są zbyt złożone i nie sprawdzają zbyt wielu rzeczy w jednym momencie. Przez to maintenance może być bardzo drogi i czasochłonny, przez co możesz nigdy nie znaleźć wystarczających zasobów na to, by móc cieszyć się „zielonymi” raportami.

Zebranie powtarzających się czynności w większe zbiory (dotyczy testów E2E)

Jak już musimy wykonać test E2E – który może być niestabilny, ale bierzemy to na klatę – to róbmy to z głową. Być może wywalenie się w jednej sekwencji, wcale nie uniemożliwia nam pójścia z testem dalej. Czasami warto rozważyć zebranie wyników konkretnych akcji i wylistowanie ich rezultatów dopiero na sam koniec, zbierając całą masę defektów, które potencjalnie w całej tej sekwencji się ujawniły.

Załóżmy, że mamy 5 kroków formularza i mamy jeden test E2E, który ma sprawdzić pełną ścieżkę. Po drodze sprawdzamy jakieś zależności po konkretnych akcjach i na każdym z kroków wykonujemy jakąś asercję. Powiedzmy, że w pierwszym formularzu coś się wywaliło – jeśli już w tym miejscu wyłożymy nasz automat, nie mamy bladego pojęcia co się dzieje dalej. Jeśli poprawimy pierwszy krok, a test wywali się na następnym etapie weryfikacji i tak dalej, wrażenie będzie takie, że nasze poprawianie i utrzymywanie tego testu trwa bardzo długo. My też tak to będziemy czuli. Z kolei jeśli zbierzemy wszystkie nieblokujące nas defekty w np. listę, a na końcu całego przejścia wydrukujemy do pliku to, co nie zostało spełnione, otrzymamy kompletny raport z przejścia jednego testu, którego zarówno zaraportowanie jak i potencjalny maintenance będzie łatwiejszy. Co za tym idzie, będziemy musieli poświęcić mniej czasu na analizę przyczyn błędu testu oraz utrzymanie testu samego w sobie.

Podsumowanie

Jeśli choć jedna z powyższych porad sprawdzi się u Was, lub zainspiruje do innego działania, które przyniesie u Was korzyść, będę zadowolony. Pamiętajmy, by dbać o jakość nie tylko produktu, ale także projektu i tego, w jakich warunkach pracujemy.

Temat został także omówiony w podcaście w odcinku Maintenance testów automatycznych a brak czasu – 045.

One Response

  1. Wiktor pisze:

    Super, że takie podsumowanie pojawiło się w formie tekstowej – pozwala to też w jakimś stopniu łatwiej wrócić do danej myśli/podpunktu, niż szukanie konkretnej minuty i sekundy na filmie.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *