#4 Antywzorce w testowaniu oprogramowania: Testowanie niewłaściwej funkcjonalności

6 stycznia 2019 | Trochę teorii, Uczymy się!

Każdy, kto ma odrobinę doświadczenia w testowaniu oprogramowania, a zwłaszcza w pisaniu testów automatycznych, wie, jak trudne, czy nawet bliskie niemożliwości, jest uzyskanie stuprocentowego pokrycia kodu testami. W teorii da się „otestować” każdą linijkę kodu, każdą funkcjonalność, każde wejście i wyjście – wszak lista możliwych przypadków jest skończona. Praktyka jednak, podparta potrzebami biznesowymi i priorytetami sprawia jednak, że jest to zwykle raczej 100% jest Świętym Graalem, a osiągnięcie go jedną z dwunastu prac Herkulesa.

Najłatwiej osiągnąć ten poziom na „świeżym” projekcie, kiedy zaczynamy od zera. Jeżeli od początku będziemy brali w developmencie testy pod uwagę, skorzystamy z dobrodziejstwa TDD i będziemy za wszelką cenę unikać długu technologicznego istnieje szansa, że pokrycie na poziomie 100% uda się utrzymać przez spory czas. W teorii brzmi to pięknie. Zwykle natomiast taka projektowa tabula rasa oczekuje rychłego zapisania w postaci ROI (zwrotu z inwestycji) – to w tym momencie jest najsilniejsze parcie na ukończenie aplikacji, a to sprzyja powstawaniu długu technologicznego. A często najbardziej kuszące jest pominięcie testów.

Inną rzeczą jest, że „świeżynki” to tylko jakaś część wszystkich rozwijanych aplikacji (moje doświadczenie podpowiada, że mówimy raczej o małym procencie). Większość z nas nie będzie miało tylko szczęścia, by z wymarzoną częstotliwością zaczynać od zera. Zwykle dziedziczymy projekty po kimś, kto je rozwijał (z – uwaga – wspomnianym długiem technologicznym). Aplikacja taka może mieć (jeśli sprzyja nam Fortuna) minimalną liczbę testów, a czasem może nie mieć ich wcale. A nasze adoptowane dziecko musi się dalej rozwijać.

Romantyczna (i czasochłonna) idea pisania testów zarówno dla nowego, jak i odziedziczonego kodu może szybko legnąć w gruzach, odrzucona przez kierownika projektu – biznes jest raczej zainteresowany maksymalną koncentracją na dodawaniu nowych funkcjonalności, refaktoryzacja jest raczej rozpatrywana w kategoriach przykrego obowiązku i to też raczej wtedy, kiedy już wisimy nad krawędzią przepaści.

Cóż więc nam pozostaje, musimy znaleźć odpowiednią równowagę pomiędzy dodawaniem testów do nowych funkcji i rozszerzeniem istniejącego zestawu testów (to drugie sprawi, że i nowe funkcje z trudem uzyskają magiczne 100% – z czegoś trzeba zrezygnować).

I tu przechodzimy do sedna tematu – w takiej sytuacji (nie tak rzadko występującej, jak już wspomniałam) istnieje ryzyko, że zmarnujemy nasze zasoby – czas i energię – na testowanie czegoś, co nie przyniesie nam dostatecznej wartości.

Załóżmy, że nasza aplikacja to sklep elektroniczny (przykład z Codepipes Blog). W czasie testowania znaleźliśmy dwa błędy:

  • użytkownik może sprawdzić zawartości swojego koszyka, co sprawia, że sprzedaż jest niemożliwa
  • użytkownik otrzymuje złe rekomendacje podczas przeglądania produktów.

Oba błędy powinny zostać naprawione, ale już na pierwszy rzut oka widzimy, że jeden z problemów ma wyższy priorytet. Wychodząc z tego założenia – niejako przewidując pewne problemy – możemy więc wybrać, który element aplikacji jest bardziej odpowiedni do zautomatyzowania (w tym wypadku powinniśmy raczej skupić się na testach koszyka niż systemu rekomendacji).

W skrócie naszą aplikację możemy podzielić na trzy części (model mentalny zaproponowany przez Codepipes:

  • Krytyczny kod – jego wpływ na użytkowanie aplikacji jest największy, w jego zakresie wprowadzane są zmiany najczęściej; ma też największą tendencję do ujawniania usterek
  • Kod podstawowy – czasem się psuje, dostaje kilka nowych funkcji i ma średni wpływ na użytkowników aplikacji
  • Pozostały kod – rzadko jest zmieniany, najrzadziej otrzymuje nowe funkcje i ma minimalny wpływ na użytkowników aplikacji.

Jak więc wybrać część naszej aplikacji, którą powinniśmy pokryć testami? Wystarczy odpowiedzieć na pytanie, czy funkcjonalność, którą obecnie testujemy, należy do kategorii krytycznych lub podstawowych. Jeśli tak, to warto napisać test. Jeśli nie, z czystym sumieniem możemy skupić się na innych zadaniach i wykorzystać nasze zasoby na coś, co przyniesie większą wartość projektowi (niekoniecznie w zakresie automatyzacji czy pisania przypadków testowych).

Próbując więc osiągnąć jak najwyższy poziom pokrycia testami powinniśmy więc raczej robić to stopniowo: najpierw osiągnąć mityczne 100% dla krytycznych funkcjonalności. A dopiero wówczas, gdy to osiągniemy, skupić uwagę na kodzie o niższym stopniu krytyczności. Testowanie funkcjonalności na chybił-trafił lub po prostu „od góry”, nie biorąc pod uwagę żadnej priorytetyzacji, nie ma raczej dużej szansy na przyniesienie największych korzyści.

Najnowsze wpisy

CzytanQA: Duch w sieci

Gdyby ktoś zapytał mnie o największego trolla w historii IT, to bez mrugnięcia okiem odpowiedziałabym: Kevin Mitnick. A jego autobiografia, napisana wespół z Williamem L. Simonem jest tego najlepszych dowodem.

#4 Antywzorce w testowaniu oprogramowania: Testowanie niewłaściwej funkcjonalności

Każdy, kto ma odrobinę doświadczenia w testowaniu oprogramowania wie, jak trudne jest uzyskanie stuprocentowego pokrycia kodu testami.

CzytanQA: Social skills for information security professionals

Kiedy tylko Dawid Bałut na swoim profilu poinformował, że jego pierwsza anglojęzyczna książka jest już dostępna, od razu wiedziałam, co następne pojawi się w serii CzytanQA.

Pin It on Pinterest

Podoba Ci się wpis?

Podziel się ze znajomymi!