biurko z komputerem w ciemnym pomieszczeniu

Automatyzacja jakości. Czy testowanie przynosi mierzalne korzyści?

Mało jest obszarów w IT, które wzbudzają tyle skrajnych emocji jak testowanie. Trudno spotkać osobę, która nie ma o nim wyrobionego zdania. Można je kochać, można nienawidzić, a można też traktować jak zło konieczne. Rzadko kto jest jednak obojętny w stosunku do tego etapu pracy nad oprogramowaniem. Czy testowanie przynosi mierzalne korzyści?

Tomasz Bondaruk

Kilka miesięcy temu opowiedzieliśmy, jak w realiach międzynarodowej korporacji stworzyliśmy jako zespół własny produkt, który sami utrzymujemy, reklamujemy i rozwijamy (więcej można przeczytać tutaj).

Dzisiaj chcemy podzielić się naszymi doświadczeniami z zakresu dbania o jakość oprogramowania oraz wdrażania procesów testowania oprogramowania. Jest to opowieść dotycząca nie tylko naszego produktu, ale również naszych wcześniejszych doświadczeń, w których byliśmy częścią innych, dużych projektów i podczas których staraliśmy się dokładać swoje cegiełki, aby jakość nie przerodziła się w jakoś.

Show me the money!

O potrzebie testowania napisano wiele i nie chodzi nam o to. Warto jednak nadmienić, że testowanie przynosi widoczne korzyści. Szczególnie w sytuacji, w której jesteśmy odpowiedzialni za własne rozwiązanie, które oferujemy różnym klientom. Wtedy na szali nie mamy jedynie większej lub mniejszej liczby błędów, ale również zaufanie, markę oraz postrzeganie przez odbiorcę – cechy, które łatwo stracić i bardzo trudno odbudować.

Wspomnimy jedynie o dwóch aspektach i zaletach wynikających z zaangażowania się w testowanie.

Koszt naprawy błędów

Błędy były, są i będą. Nie ma rozwiązania IT, które nie miałoby błędów i nasze nie jest wyjątkiem. Warto jednak zastanowić się, co możemy z tym zrobić. Znanym i często pokazywanym wykresem jest relatywny koszt naprawy błędów w zależności od etapu projektu:

wykres kosztu naprawy błędów

Im później, tym naprawa jest droższa. Kosztem, jaki ponosimy, nie muszą być pieniądze. Może to być czas, opóźnienie wdrożenia czy potrzeba większego przemodelowania systemu.

Re-używalność

Drugim, równie istotnym elementem i czynnikiem wpływającym na potrzebę regularnego i efektywnego testowania naszego produktu jest to, jak jest on zbudowany. CDP jest narzędziem składającym się z komponentów, które łączymy, tworząc kolejne implementacje. Jeżeli dla jednego klienta dany komponent rozbudujemy, to kolejny będzie korzystał z ulepszonego zestawu funkcji, tworząc efekt synergii. Takie rozwiązanie daje nam elastyczność, ale zastawia również pułapkę — błędy multiplikują się i wszyscy klienci na nich tracą.

Z tego powodu największy nacisk kładziemy na testowanie i analizę tych komponentów, które są najbardziej re-używalne oraz funkcji wykorzystywanych najczęściej. Naszym celem jest możliwe zminimalizowanie problemów, które na późniejszym etapie będą się skalować.

Przeciwności losu

Zarówno w trakcie prac nad naszym produktem, jak i wcześniej spotykaliśmy się różnego rodzaju oporem przed procesem testowania. Był to najczęściej opór ludzki, pochodzący z różnych stron. Czy to od strony programistów, z którymi byliśmy w zespole, od innych równoległych zespołów czy od szeroko rozumianego kierownictwa. Powody, dla których testy były spychane na dalszy plan były różnorakie i tutaj chcemy przywołać kilka, które najbardziej utkwiły nam w pamięci.

  • Brak czasu

Jest to chyba najczęściej podnoszony argument. Na testy nigdy nie ma czasu, zawsze coś jest ważniejsze. Z tym stwierdzeniem spotykaliśmy się zarówno od naszych współpracowników, jak i kierownictwa. Aby przeciwdziałać takiemu podejściu, staraliśmy się uzmysłowić, że jest to inwestycja mająca na celu ograniczyć koszty, które należy ponieść w przyszłości. Odwołanie się do wykresu, który opisaliśmy wcześniej, pozwala jasno pokazać, jak taka inwestycja zwraca się w długiej perspektywie.

  • Inne priorytety — nowe funkcje zamiast testów

Jest to równie, jak nie bardziej częste wyjaśnienie, dlaczego proces testowy jest odkładany na później. W każdym momencie nowe funkcje są ważniejsze, zawsze jest jakiś deadline, jakiś kamień milowy, na którym należy się skupić. A do testów może wrócimy później…

W takim przypadku należy znaleźć odpowiedni balans. Nie wywrócimy harmonogramu projektu, podejmując decyzję, że opóźniamy projekt o 3 miesiące, gdyż chcemy pokrycie testowe zwiększyć z 15% do 75%, ponieważ możemy utracić projekt bezpowrotnie. Warto jednak wspólnie z „biznesem”, na podstawie podnoszonych wcześniej argumentów, ustalić priorytet dla testów i odpowiednio zaplanować dojście do stanu docelowego.

Jedną z metod, które nam pomogły na jednym z projektów, jest zawyżanie estymacji każdego z zadań o x punktów, które miały być przeznaczone na wysiłek testowy. Dzięki temu nadal można było planować projekt, jak również mieć czas na dbanie o jakość.

  • Stan zastany

Każdy z nas spotkał się przynajmniej raz z projektem, który ma wiele nie przetestowanych linii kodu. Cały zespół chce pisać testy, ale ogrom starego, niezbadanego kodu jest tak wielki, że przytłacza, zniechęcając już na samym początku. My także staliśmy przed tym problemem, gdy przejmowaliśmy odpowiedzialność za moduły napisane przez inne zespoły. Podjęliśmy wtedy wraz z Product Ownerem decyzję, że KPI dotyczące jakości, będziemy obliczać tylko dla nowego kodu pisanego w ramach tych modułów, a pokrycie testami pozostałych części kodu będzie dokonywane podczas refactoru bądź planowane jako osobne zadania w ramach Sprintów.

  • Niechęć członków zespołu

Innym, ale jakże częstym problemem, jaki napotkaliśmy (i zapewne, Wy drodzy czytelnicy również napotykacie) jest niechęć części członków zespołu do zagadnienia testów. Najbardziej jaskrawym przypadkiem był jeden z programistów, z którym mieliśmy okazję pracować. Był on wręcz agresywnie nastawiony do zagadnienia i twierdził, że „jeszcze nigdy nie widział, żeby testy jednostkowe znalazły jakieś błędy” lub „jeżeli chcecie sobie pisać testy to piszcie, ale on nie zamierza”.

W radzeniu sobie z takim nastawieniem bardzo pomocna była otwarta postawa naszego Agile Mastera oraz determinacja zespołu. Mimo prób tłumaczenia i przekonywania, że testy jednostkowe nie są od znajdowania błędów, bardziej od zabezpieczania poprawności działania (nasz Test Architekt uwielbiał bardzo trafne porównanie do lin zabezpieczających podczas wspinaczki górskiej) jego postawa była nieprzejednana. Ostatecznie rozwiązaniem była demokratyczna decyzja większości zespołu o tym, jak mają wyglądać wewnętrzne procesy i lekkie przymuszenie go do współpracy.

Manual vs Automated

Od początku budowy naszego produktu kładliśmy nacisk na automatyzację procesu testowania. Chcieliśmy dzięki temu uzyskać następujące korzyści:

  • szybkość wykonywania testów
  • wysokie pokrycie kodu oraz przypadków testowych
  • pewność, że za każdym razem wszystko zostanie przetestowane

Dodatkowo chcieliśmy, aby proces testowy był immanentną częścią procesu budowania aplikacji. Wiele projektów, które widzieliśmy, rozdzielało te elementy. Z jednej strony był proces budowania i wdrażania systemu na poszczególne środowiska a z drugiej testowanie. My chcieliśmy to połączyć, aby nieprzechodzące testy blokowały możliwość wdrażania kolejnej wersji systemu. Dodatkowo nie tylko testy, ale również metryki jakościowe dot. kodu są włączone w proces budowania, więc tzw. „code smells” mogą zablokować proces wdrażania.

Mimo automatyzacji część pracy pozostaje w rękach członków zespołu. W przypadku dużych systemów jest to zadanie testerów, ale my, podążając za rekomendacją zwinnego podejścia do testów: „w Agile’owym zespole każdy jest testerem” dzielimy się tymi obowiązkami. Ręcznie dokonujemy tzw. „exploratory tests”, czyli sprawdzania przypadków nieoczywistych, nietypowych i krańcowych. Chodzi o to, aby uzyskać sytuację, w której automat testuje za nas sytuacje typowe, a człowiek zajmuje się tylko obszarami nadzwyczajnymi (przez co najciekawszymi).

Technologie

Testy w naszym produkcie zorganizowane są zgodnie z rekomendacją Test Architekta, z którym mamy przyjemność współpracować. Opieramy je na tzw. piramidzie testów.

piramida testów

Zgodnie z nią bazujemy na testach jednostkowych, które indywidualnie testują każdą z funkcji naszego systemu. Następnie testy integracyjne, GUI oraz manualne. Osiągnięty efekt powoduje, że każda z kolejnych części (będąca coraz bardziej skomplikowana) bazuje na dokładnie przetestowanej warstwie poprzedniej.

Warto przy okazji wspomnieć, że wiele systemów czy projektów, na których pracowaliśmy (i, przy których na pewno mają okazję pracować nasi czytelnicy) bazuje na odwróconej piramidzie.

owdrócona piramida testów

W takim przypadku większość wysiłku testowego oparte jest na testach GUI czy manualnych, a te prowadzić mogą do błędnych wniosków. Pomiędzy jedną akcją na interfejsie użytkownika a wykonaniem tej akcji zachodzić może wiele niepożądanych zjawisk i taki test (niepoparty wcześniej sprawdzeniem każdej z warstw pośrednich) nie daje nam wiele wiedzy poza tym, że „coś” nie działa.

Na temat technologii nie będziemy się rozpisywać, ponieważ każdy z tych elementów zasługuje na osobny artykuł opisujący szczegóły poszczególnych frameworków.

JUnit/TestNG

Back-end naszego produktu jest oparty o język Java, stąd wybór frameworka testowego nie powinien dziwić. Początkowo wykorzystywaliśmy TestNG, jednak wraz z pojawieniem się na rynku JUnit 5 przeszliśmy na niego.

Robot Framework

Do testów na nieco wyższym poziomie wykorzystujemy Robot Framework. Jest to framework oparty na Python pozwalający na przeprowadzenie bardzo różnorodnych testów. Dzięki mnogości dostępnych bibliotek możliwe jest testowanie baz danych, szyny integracyjnej, interfejsów. Dodatkowo prostota składni gwarantuje niski próg wejścia dla osób, które nie są zaznajomione z tą metodą testowania. Jako że Robota można w prosty sposób połączyć z Selenium, to może być on doskonałym sposobem na wykonanie testów wszystkich warstw, począwszy od integracji, na GUI skończywszy.

Automatycznie generowane raporty z wykonanych testów są dodatkowym atutem i zaletą zachęcającą do skorzystania z tej biblioteki.

SonarQube

Do zarządzania jakością kodu używamy połączenia SonarQube oraz SonarLint. Są to uznawane w środowisku narzędzia, więc nie ma powodu, aby się nad nimi szczegółowo pochylać. Warto wspomnieć, że metryki, jakie zwraca analiza Sonar, są wykorzystywane do ewentualnego zatrzymania procesu budowania. Dzięki temu, nawet jeżeli ktoś nie ma ochoty, to musi zająć się poprawą jakości kodu.

Security

W naszej organizacji istnieje specjalna komórka zajmująca się badaniem bezpieczeństwa aplikacji. Nawiązaliśmy z nimi współpracę, aby dodatkowo zabezpieczyć bezpieczeństwo naszego produktu. Otrzymaliśmy licencję do narzędzia Veracode pozwalającego na skanowanie kodu pod kątem problemów z bezpieczeństwem. Jest to bardzo sprawna, intuicyjna i szybka platforma, którą z chęcią polecamy wszystkim czytającym do sprawdzania bezpieczeństwa Waszych aplikacji.

Co dalej?

Przygoda z testowaniem i zapewnieniem jakości naszego produktu nie zakończyła się i nigdy się nie skończy. Chcemy cały czas się rozwijać i tak jak rośnie nasza baza klientów, dodajemy nowe funkcje do możliwości naszego narzędzia, tak i baza testów się ciągle powiększa.

Mamy też kolejne pomysły co chcielibyśmy zrobić w przyszłości takie jak:

  • automatyczne skanowanie kodu pod kątem licencji i zagadnień związanych z Open Source, aby badać nie tylko techniczną, ale również prawną poprawność naszego kodu,
  • zautomatyzowane tworzenie środowiska testowego tylko na czas wykonywania testów, a następnie jego usuwanie – „wirtualne” środowisko Q,
  • i wiele innych.

Morał

Zorganizowanie i stworzenie procesu automatycznego testowania wiele nas nauczyło. Jak pokazuje nasza historia, niechęć programistów nie jest jedyną przeciwnością, jaka może stać na drodze do zapewnienia odpowiedniego zabezpieczenia produktu IT.

Pokonanie ich nie było łatwym zadaniem, ale widzimy kilka kluczowych elementów, które wpływają na sukces całego przedsięwzięcia:

  • chęć i wola programistów — bez niej, nawet najlepiej zorganizowany proces nie zadziała,
  • przekonanie osób wątpiących — uzmysłowienie zalet, jakie stoją za proponowanym rozwiązaniem i właściwe zidentyfikowanie ich potrzeb (dla jednych będzie to oszczędność czasu w przyszłości dla innego brak potrzeby wracania do starego kodu),
  • możliwie maksymalna automatyzacja procesu — dzięki temu osiągamy pewność wykonania procesu testowego, jak również jego nieuchronność.

Nic z tego nie udałoby się, gdyby nie wspaniały zespół zmotywowanych ludzi: Anna Raźna, Marcin Kierdelewicz, Wojciech Walicki jak również osób, które nas wspierają Grzegorz Bąk, Paweł Szymczak, Łukasz Rzegociński oraz Łukasz Michałowski.

Zdjęcie główne artykułu pochodzi z unsplash.com.

Zapraszamy do dyskusji

Patronujemy

 
 
More Stories
wypalenie zawodowe
Pójdziemy na L4, jeśli czujemy wypalenie zawodowe. Zmiany od przyszłego roku