niedziela, 9 września 2007

Testowanie w projektach zwinnych

W ciągu ostatnich trzech tygodni byłem trzy razy pytany o to jak testować oprogramowanie powstające z wykorzystaniem procesów zwinnych. Pytały trzy różne, niezależne osoby. Oznacza to, że temat jest ciekawy. To co poniżej napiszę to tylko wstęp, ale na początek powinien wystarczyć.

Opiszę jak w podejściu zwinnym odbywa się (powinno się odbywać) testowanie na poziomach testowania jak zdefiniowanych tutaj.

Testowanie komponentów
To jest najprostsze. Testowanie komponentów musi odbywać się obowiązkowo w każdym projekcie realizowanym z użyciem metod zwinnych. Testowanie komponentów zawsze powinno być automatyczne. W zależności od tego w jaki sposób zespół jest przyzwyczajony pracować absolutnym minimum jest napisanie testów automatycznych pokrywających 100% napisanego kodu. Sytuacją dającą najlepsze rezultaty jest programowanie z nastawieniem "najpierw testy" oraz używanie środowiska ciągłej integracji. Chodzi mniej więcej o to, aby w sposób automatyczny wykonywały się testy całości do tej pory zaimplementowanej funkcjonalności. Po każdej zmianie kodu całość powinna być rekompilowana i testy powinny wykonywać się automatycznie. Najlepiej aby raporty z wykonania tych testów były w jakiś sposób publikowane, tak aby każdy mógł je zobaczyć. Na przykład na jakiejś stronie intranetowej.

Takie podejście jest absolutnie konieczne ze względu na dużą zmienność występującą w systemach wytwarzanych metodami zwinnymi. Jeżeli zaniedba się testy automatyczne to po kilku iteracjach w kodzie zapanuje chaos i nie będzie wiadomo co działa a co nie. Gwarantowane.

Testowanie integracji
Uwaga! Poniższe dotyczy testów integracji komponentów. Nie odnosi sie to testowania integracji systemów.

Testy integracyjne należy również zautomatyzować na ile tylko się da. Podstawowe testy integracyjne powinny być wykonywane w środowisku ciągłej integracji, czyli tak często jak się da. Najrzadziej co noc. Problem pojawia się wtedy kiedy mamy się integrować z niestabilnymi komponentami, na przykład tworzonymi równolegle przez zespoły pracujące metodami zwinnymi. Będzie to problematyczne, ale też należałoby tutaj zautomatyzować takie testy do granic, gdzie się da. Zwykle będzie to wymagało dokładnego dogadania się z innymi zespołami na temat wykorzystywanych interfejsów. Brzmi trudno, ale w praktyce powinno być tak, że mniej więcej w połowie iteracji zespoły powinny znać szczegóły interfejsów zewnętrznych swojego komponentu. To powinno zaś umożliwić zautomatyzowanie testów. Trzeba tylko uważać na ewentualne zależności w funkcjonalności poszczególnych komponentów. Takie zależności powinny być rozwiązywane na poziomie zarządzania zwinnego projektem a dokładnie na poziomie zarządzania wieloma zespołami. Przykładem techniki, która to umożliwia jest na przykład "scrum of scrums" - temat na osobny wpis/kilka wpisów.

Szczególną uwagę należy zwrócić na testy wydajnościowe. Ja zaliczam je do testów integracyjnych, gdyż poszczególny test wydajnościowy zwykle dotyczy tak naprawdę testowania współdziałania jednego bądź dwóch modułów systemu, rzadko kiedy całego systemu. Jeżeli komuś to nie pasuje to może uznać je za testy systemowe. W obu wypadkach podtrzymuję to co zaraz napiszę. Testy wydajnościowe powinny być wykonywane co najmniej raz na iterację. Powinny być wykonywane względem celu wydajnościowego ustalonego dla końcowego systemu w karcie ograniczeń produktu. Powinny obejmować wszystkie te funkcjonalności które są dostępne w danej iteracji. Powód takiego działania jest dość prosty. Otóż ze względu na iteracyjność tworzenia oprogramowania w sposób naturalny architektura rozwiązania może się zmieniać. W związku z tym powinno nam zależeć na jak najszybszym dowiedzeniu się czy aktualna architektura aby na pewno odpowiada wymaganiom stawianym przed systemem. Stąd testy wydajnościowe należy przeprowadzać z celami dla całego systemu przynajmniej raz na iterację, żeby było wiadome czy aktualna architektura i wykonanie systemu realizują założone cele.

Testowanie systemu
To najciekawszy poziom testowania z punktu widzenia metod zwinnych zarządzania projektami. Szczególnie ciekawy jest w przypadkach kiedy kilka zespołów pracuje nad kilkoma modułami stanowiącymi jeden system. Pytanie brzmi kiedy i jak testować całość systemu. Oczywiście odpowiedź brzmi, że w świecie idealnym powinno się to robić co iterację. Świat rzeczywisty wygląda jednak często tak, że nie ma na to czasu. Testy systemowe zwłaszcza dużych systemów potrafią trwać zbyt długo, aby można było sobie pozwolić na robienie ich w ramach jednej iteracji. Często głównym powodem jest tutaj fakt, że testy te wymagają dużej aktywności użytkownika końcowego i po prostu nie starczyłoby czasu. W związku z tym dla dużych systemów dopuszcza się dokonywanie testów systemu raz na każdą wersję (release) oprogramowania.

Wersja oprogramowania pojawia się w procesach zwinnych co kilka iteracji. Każda z iteracji ma na celu dostarczenie działającej wersji, potencjalnie mogącej być wysłaną do użytkownika ("potentially shipable product increment" - tak to jest w języku Shakespeare'a). Co kilka iteracji powstaje zaś "wersja" oprogramowania, która jest po prostu komercyjnym produktem mogącym iść na sprzedaż bądź być wdrożonym u klienta. Oczywiście zdarzają się przypadki, kiedy wersja powstaje w każdej iteracji, lecz doświadczenie wskazuje, że są to wtedy raczej mniejsze systemy. Systemy większe, takie które będą miały konieczność dokonania testowania systemu zwykle będą planowane na obu poziomach: wersji i iteracji. Dlaczego o tym piszę? Otóż w takich przypadkach zwykle ostatnia iteracja w wersji jest przeznaczana na testy systemowe. Zakłada się, że wartością dodaną w takiej iteracji jest dostarczenie w pełni zintegrowanego systemu. Oczywiście testy systemowe niekoniecznie muszą zajmować całą iterację. Ale na pewno przyczynią się do zmniejszenia ilości zaimplementowanej nowej funkcjonalności.

Testy akceptacyjne
Tutaj sprawa jest prosta: testy akceptacyjne wykonuje klient po przekazaniu mu każdej jednej wersji do testów. Ze względu na bliskie zaangażowanie klienta możliwe jest przekazywanie produktu nie mającego zaimplementowanych wszystkich funkcjonalności i otrzymywanie natychmiastowej informacji zwrotnej o postępach prac. W przypadku bardzo dobrej współpracy między klientem a dostawcą możliwe jest nawet przekazywanie klientowi zawierającego błędy oprogramowania w środku iteracji - po to, aby sprawdził czy koncepcja zaimplementowania którejś z funkcjonalności odpowiada jego potrzebom.

Brak komentarzy: