#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 nie 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

Quality Excites 2019

Wczoraj zakończyła się 8. edycja konferencji Quality Excites, w ramach której miałam okazję prowadzić panel dyskusyjny. Wnioski z dyskusji umieszczę tutaj wkrótce, a dziś zachęcam Was do przeczytania podsumowania moich wrażeń z tego wydarzenia.

test:fest 2019 – podsumowanie

Czas na recenzję Test:fest – bez wątpienia jednego z bardziej rozpoznawalnych testerskich wydarzeń w Polsce.

Quality Meetup #19 – podsumowanie

Już ponad miesiąc minął, odkąd wystąpiłam na Quality Meetup ze swoją prezentacją poświęconą błędom poznawczym. A jeszcze więcej od ostatniego wpisu na blogu. Czas najwyższy więc na dobre wyjść ze snu zimowego i zacząć nadrabiać.

Pin It on Pinterest

Podoba Ci się wpis?

Podziel się ze znajomymi!