Testowanie oprogramowania. Podręcznik dla początkujących

Testuj programy i śpij spokojnie! Ogólna teoria testowania, czyli po co nam testy i jak sobie z nimi radzić Projekt a pr

587 138 4MB

Polish Pages [201] Year 2014

Report DMCA / Copyright

DOWNLOAD FILE

Polecaj historie

Testowanie oprogramowania. Podręcznik dla początkujących

Table of contents :
Spis treści
Przedmowa (5)

Wstęp (7)

Rozdział 1. Ogólna teoria testowania (11)

1.1. Techniki testowania (13)
1.2. Miara jakości oprogramowania (17)
1.3. Środowisko testowe i produkcyjne (23)
1.4. Replikacja błędów (28)
1.5. U mnie błąd nie występuje (30)
1.6. Symulatory aplikacji oraz generatory danych (31)
1.7. Dokumentowanie testów (34)
1.8. Kontrola wersji oprogramowania (35)
1.9. Obsługa zgłoszeń (39)
1.10. Testowanie obsługi wyjątków w kodzie (43)
1.11. Narzędzia wsparcia pracy testera (51)
1.12. Presja czasu (52)
1.13. Profil profesjonalnego testera (54)
1.14. Testowanie w oknie czasu (58)
1.15. Jak wygląda realizacja projektu w praktyce? (60)
1.16. Testowanie w cyklu życia oprogramowania (62)
Rozdział 2. Poziomy wykonywania testów (65)

2.1. Testy modułowe (66)
2.2. Testy integracyjne (67)
2.3. Testy systemowe (71)
2.4. Testy akceptacyjne (72)
Rozdział 3. Typy testów (73)

3.1. Testy funkcjonalne (73)
3.2. Testy niefunkcjonalne (74)
3.2.1. Testy wydajności (74)
3.2.2. Testy bezpieczeństwa aplikacji (91)
3.2.3. Testy przenośności kodu - testy instalacji (117)
3.2.4. Testy ergonomii systemu informatycznego (118)
3.3. Testy regresywne (125)
Rozdział 4. Wprowadzenie do projektowania testów (129)

4.1. Projektowanie testu w oparciu o technikę czarnej skrzynki (131)
4.1.1. Wartości brzegowe (131)
4.1.2. Przejścia pomiędzy stanami (134)
4.1.3. Projektowanie testu w oparciu o przypadki użycia (135)
4.2. Projektowanie testu w oparciu o technikę białej skrzynki (136)
4.3. Projektowanie testu w oparciu o doświadczenie testera (140)
4.4. Przypadki testowe w ujęciu praktycznym (140)
Rozdział 5. Psychologiczne aspekty procesu testowania (149)

Rozdział 6. Syndrom zniechęcenia testami (153)

Rozdział 7. Testowanie usług sieciowych (165)

7.1. Narzędzie SoapUI - klient usługi sieciowej (165)
7.2. Symulator serwera usług sieciowych - SoapUI Mock Services (171)
7.3. Monitor TCP - Apache TCPMon (177)
Rozdział 8. Wprowadzenie do automatyzacji testów (183)

Dodatek A. Generowanie sumy kontrolnej (187)

Dodatek B. Membrane SOAP Monitor (189)

Dodatek C. Wireshark - analizator ruchu sieciowego (195)

Dodatek D. Generowanie danych testowych (197)

O autorze (207)

Skorowidz (209)

Citation preview

Rafał Pawlak

TESTOWANIE OPROGRAMOWANIA Podręcznik dla początkujących

Testuj program y i śpij spokojnie! * Ogólna teoria testowania, czyli po co nam testy i jak sobie z nimi radzić * Projekt a proces testowania, czyli kiedy zacząć testować i jak to robić z głową * Automatyzacja i dokumentacja, czyli jak ułatw ić sobie pracę podczas testowania

Helion

Spis treści Przedmowa ................................................................................................................. 5 W stęp..........................................................................................................................7 Rozdział 1. Ogólna teoriatestowania ...................................................................... 11 1.1. Techniki testow ania..........................................................................................................13 1.2. Miara jakości oprogramowania ...................................................................................... 17 1.3. Środowisko testowe i produkcyjne ................................................................................ 23 1.4. Replikacja błędów ........................................................................................................... 28 1.5. U mnie błąd nie występuje ............................................................................................. 30 1.6. Symulatory aplikacji oraz generatory danych............................................................... 31 1.7. Dokumentowanie testów .................................................................................................34 1.8. Kontrola wersji oprogramowania ...................................................................................35 1.9. Obsługa zgłoszeń..............................................................................................................39 1.10. Testowanie obsługi wyjątków w kodzie ..................................................................... 43 1.11. Narzędzia wsparcia pracy te ste ra................................................................................. 51 1.12. Presja czasu .................................................................................................................... 52 1.13. Profil profesjonalnego testera .......................................................................................54 1.14. Testowanie w oknie czasu ............................................................................................ 58 1.15. Jak wygląda realizacja projektu w praktyce?..............................................................60 1.16. Testowanie w cyklu życia oprogramowania...............................................................62

Rozdział 2. Poziomy wykonywania testów ..............................................................65 2.1. 2.2. 2.3. 2.4.

Testy Testy Testy Testy

modułowe ...............................................................................................................66 integracyjne............................................................................................................ 67 systemowe...............................................................................................................71 akceptacyjne .......................................................................................................... 72

Rozdział 3. Typy testów ...........................................................................................73 3.1. Testy funkcjonalne .......................................................................................................... 73 3.2. Testy niefunkcjonalne......................................................................................................74 3.2.1. Testy w ydajności....................................................................................................74 3.2.2. Testy bezpieczeństwa aplikacji ............................................................................ 91 3.2.3. Testy przenośności kodu — testy instalacji.......................................................117 3.2.4. Testy ergonomii systemu informatycznego ...................................................... 118 3.3. Testy regresyw ne............................................................................................................125

4

Testowanie oprogramowania. Podręcznik dla początkujących

Rozdział 4. Wprowadzenie do projektowania testów ............................................ 129 4.1. Projektowanie testu w oparciu o technikę czarnej skrzynki...................................... 131 4.1.1. Wartości brzegowe ...............................................................................................131 4.1.2. Przejścia pomiędzy stanam i.................................................................................134 4.1.3. Projektowanie testu w oparciu o przypadki u ży cia...........................................135 4.2. Projektowanie testu w oparciu o technikę białej skrzynki ........................................ 136 4.3. Projektowanie testu w oparciu o doświadczenie testera ............................................140 4.4. Przypadki testowe w ujęciu praktycznym.....................................................................140

Rozdział 5. Psychologiczne aspekty procesu testowania...................................... 149 Rozdział 6. Syndrom zniechęcenia testami ........................................................... 153 Rozdział 7. Testowanie usług sieciowych ..............................................................165 7.1. Narzędzie SoapUI — klient usługi sieciowej ............................................................. 165 7.2. Symulator serwera usług sieciowych — SoapUI Mock Services .............................171 7.3. Monitor TCP — Apache T C P M on.............................................................................. 177

Rozdział 8. Wprowadzenie do automatyzacji testów ............................................. 183 Dodatek A Generowanie sumy kontrolnej ............................................................. 187 Dodatek B Membrane SOAP Monitor .................................................................... 189 Dodatek C Wireshark — analizator ruchu sieciowego .........................................195 Dodatek D Generowanie danych testowych ......................................................... 197 O autorze ................................................................................................................207 Skorowidz ..............................................................................................................209

Wstęp Testowanie oprogramowania to proces zapewnienia jakości oprogramowania. „Ja­ kość” to termin określający stopień zgodności implementacji kodu z oczekiwaniami, potrzebami i założonymi wymaganiami postawionymi przez zamawiającego. Jakość to miara określająca, w jakim stopniu oprogramowanie spełnia wymagania biznesowe oraz zaspokaja oczekiwania klienta. Jakość oprogramowania można opisywać poprzez jego atrybuty, które zostaną wstępnie omówione w rozdziale 1.2. Testowanie to proces obejmujący wszelkie czynności mające na celu potwierdzenie zgodności zaproponowanych rozwiązań ze specyfikacją wymagań. Celem testowania jest wykrywanie i raportowanie błędów. Za błąd należy uważać pomyłkę programisty, której skutkiem jest niepożądane zachowanie aplikacji. Proces testowania ujawnia odchyle­ nia od założonego działania systemu poprzez porównanie otrzymanego wyniku testu z oczekiwanym rezultatem. Błąd w wykonywanym kodzie znajdzie swoje odwzoro­ wanie w postaci niepoprawnego zachowania programu. Na potrzeby niniejszej publikacji przyjmijmy uogólnienie, że błąd to nieoczekiwane zachowanie systemu na skutek pomyłki programisty. Jako błąd traktujmy rozbieżno­ ści w działaniu systemu w porównaniu z wyspecyfikowanymi wymaganiami. Błędem będziemy nazywać widoczny skutek, a nie przyczynę (wadę kodu). Oczywiście jedno wynika z drugiego. Niemniej jednak w tej publikacji oba pojęcia mogą się delikatnie przenikać. Notabene jest to odmienne podejście od prezentowanego w ramach kursu ISTQB, gdzie błędem jest pomyłka człowieka, która wywołuje defekt w programie, a wykonanie kodu z defektem zwykle skutkuje awarią. Intencją testowania oprogramowania jest zmniejszenie ryzyka wystąpienia błędu w śro­ dowisku produkcyjnym. Wczesne wykrycie błędu zmniejsza koszty jego naprawy oraz minimalizuje potencjalne konsekwencje. Wystąpienie niepożądanego zdarzenia w śro­ dowisku produkcyjnym wiąże się z wysokimi kosztami poprawy oraz generowaniem strat w postaci utraconych korzyści biznesowych (np. czasowa blokada możliwości realizowania zakupów w sklepie internetowym realnie wpłynie na wyniki finansowe przedsiębiorstwa). Do negatywnych skutków błędów produkcyjnych należy również zaliczyć ujmę w wizerunku oraz obniżenie zaufania do podmiotu (np. operatora, który czasowo stracił zdolność do obsługiwania transakcji kartą).

8

Testowanie oprogramowania. Podręcznik dla początkujących

Testowanie oprogramowania umożliwia zmierzenie jakości produktu. Wskaźnikiem oceny jest liczba wykrytych błędów. Jeżeli w całym projekcie testowym znaleziono mało błędów, tym samym podnosi się zaufanie do wytworzonego kodu. Testy winny być zaprojektowane w sposób miarodajny. Luki w pokryciu testami aplikacji mogą za­ fałszować ostateczną ocenę stanu systemu. Zgodnie z nauką ISTQB samo testowanie nie podnosi jakości oprogramowania. Jakość systemu wzrasta dopiero wtedy, gdy owe problemy zostaną rozwiązane. Podstawowa prawda o testowaniu mówi, że testy nie są w stanie udowodnić, iż w aplika­ cji błędów nie ma. Testy wykrywają błędy, ale nie udowadniają bezbłędności programu, nawet jeżeli wszystkie założone przypadki testowe zostaną zakończone pozytywnie. Podjęcie testów powinno nastąpić tak wcześnie, jak jest to możliwe. Rozpoczęcie czyn­ ności dopiero po etapie kodowania jest bardzo ryzykowne i stanowczo spóźnione. Testy powinny rozpocząć się już na etapie analizy i projektowania. Materiałem podlegającym weryfikacji będzie powstała dokumentacja. Testerzy w oparciu o rzeczywiste doświad­ czenia mogą wychwycić błędne założenia, których skorygowanie na etapie specyfikowania uchroni przedsięwzięcie od dodatkowych kosztów. Implementacja wadliwie zaprojektowanych rozwiązań podniesie kilkukrotnie koszty naprawienia błędu. Czynno­ ści testowe muszą być rozpoczynane we wczesnych fazach cyklu życia oprogramowania. Druga prawda o testowaniu mówi, że testy powinny kiedyś się zakończyć, mimo że nigdy nie nabierzemy przekonania o bezbłędności programu. Decyzja o przerwaniu testów uzależniona jest od poziomu ryzyka, prawdopodobieństwa wystąpienia sytu­ acji niepożądanych oraz płynących z owych zdarzeń konsekwencji. Testy gruntowne — tj. uwzględnienie wszystkich warunków wstępnych i kombinacji danych wejścio­ wych — są niemożliwe. Ograniczenia ekonomiczne oraz brak uzasadnienia praktycz­ nego negują potrzebę kontynuowania testów w nieskończoność. Kluczem do sukcesu jest trafne wytypowanie momentu zakończenia testów. Warunkiem koniecznym jest zamknięcie wszystkich przypadków testowych z wynikiem pozytywnym. Niestety nad wymienionym kryterium często biorą górę tak zwane decyzj e polityczne maj ące na celu skrócenie terminu przekazania produktu klientowi (świadome przekazywanie produktu z ujawnionymi i niepoprawionymi błędami, emisja bez przeprowadzenia pełnych testów). Zamknięcie przypadków testowych uwiarygodnia pogląd, że cel pro­ jektu został osiągnięty. Istotą sukcesu jest optymalne zaplanowanie testów i prawi­ dłowe zaprojektowanie przypadków testowych. Ta tematyka będzie analizowana w ko­ lejnych rozdziałach książki. Trzecia prawda o testowaniu mówi, że zespół kontroli jakości może być postrzegany jako czynnik blokujący wydanie produktu klientowi w momencie, kiedy cały projekt osiągnął punkt krytyczny (datę końcową). Otóż „twórca” przedsięwzięcia polegającego na wyprodukowaniu oprogramowania zgodnego z oczekiwaniami klienta i w zadanym harmonogramie powołał grupy i powierzył im ściśle określone zadania. Ostateczne testy jakościowe wykonywane są jako jeden z ostatnich etapów w cyklu produkcji. Niestety często występującym zjawiskiem jest przekazywanie produktu do testów ja ­ kościowych ze znaczącym opóźnieniem. Rysunek W.1 ilustruje hipotetyczną sytuację, w której zespół programistów skonsumował własny czas, czas przypisany na testy wewnętrzne oraz fragment czasu zarezerwowanego na testy jakościowe (punkty A i B grafiki).

Wstęp

9

Przebieg p la n o w a n y

P ro je k to w a n ie

A naliza

K o dow anie

Testy

N iezależn e te s ty

w e w n ę trz n e

jakościow e

Przebieg rzeczyw isty

A naliza

_

|

P ro je k to w a n ie

,

K odow anie

I

I

U

A

B

Testy

N iezależne testy

w e w n ę trz n e

jakościow e

i

^ ---------------------------------------Oś czasu projektu--------------------------------------------Kary umowne ►

C

Rysunek W.1. Hipotetyczny przebieg realizacji projektu produkcji oprogramowania Zespół testów wewnętrznych (testy modułowe) rozpoczął pracę w momencie, kiedy faktycznie aplikacja powinna być już weryfikowana na etapie ostatecznych testów ja ­ kościowych (punkt B). Zatem faza, w której decyduje się o oficjalnym wydaniu pro­ duktu, rozpoczęła się niemalże przed datą finalnego zakończenia projektu (punkt C). Osiągnięcie punktu C stanowi moment krytyczny, gdyż pojawia się realna groźba utraty części zysku na skutek pokrycia kar umownych za niedotrzymanie terminu re­ alizacji umowy. Nietrudno sobie wyobrazić, że powstanie konflikt interesów pomię­ dzy kierownikiem projektu (ang. Project M anager — PM) a zespołem testów. Każdy z uczestników będzie bronił partykularnych interesów. O tym, jak się zachować w takiej sytuacji, będzie mowa w dalszych częściach książki. Istnieje zasada kumulowania się błędów. Oznacza to, że większość wykrytych pro­ blemów znajduje swoje źródło w niewielkiej liczbie modułów. W aspekcie praktycznym duża „błędogenność” określonego fragmentu kodu wygeneruje większość błędów w ca­ łościowym ujęciu aplikacji.

Rozdział 1.

Ogólna teoria testowania Warunkiem wstępnym do zgłębiania tajników testowania oprogramowania jest usys­ tematyzowanie wiedzy już posiadanej oraz ujęcie luźnych myśli i odczuć w nieco bardziej ścisłe ramy. W tym rozdziale postaramy się wypracować podstawy niezbędne do dalszego studiowania niniejszej pozycji. Testowanie to proces weryfikacji zachowania systemu i porównywanie otrzymanego rezultatu z przewidywaniami. Jednym z elementów testowania jest uruchamianie aplika­ cji w zadanych warunkach początkowych. Celem testowania jest zminimalizowanie ryzyka wystąpienia błędu w środowisku produkcyjnym oraz uzyskanie maksymalnie dużej pewności, że oprogramowanie funkcjonuje zgodnie z założeniami. Test to wykonywanie czynności polegających na uruchamianiu określonej funkcjo­ nalności w zadanych warunkach i parametrach wejściowych. Celem wykonania testu jest weryfikacja zachowania aplikacji, tj. porównanie rzeczywistego efektu z oczeki­ wanym. Test kończy się sukcesem w sytuacji, kiedy realne działanie systemu pokrywa się z przewidywaniami. Retest to nic innego jak powtórne wykonanie przypadku testowego, który uprzednio zakończył się niepowodzeniem. Wynik negatywny pierwotnego testu determinował wykonanie zmiany w kodzie w celu osiągnięcia założonego rezultatu. Ocenę skutecz­ ności poprawki realizuje się poprzez powtórzenie testu. Liczba iteracji jednego lub zbioru przypadków testowych z zadanego obszaru świadczy o skuteczności i jakości kodu przekazanego przez zespół programistów. Moduły, obszary aplikacji, które na­ znaczone są wysokim współczynnikiem powtórzeń testów, powinny być oznaczone jako elementy o podwyższonym ryzyku. Pośrednio płynącym wnioskiem ze znacznej ilości retestów może być personalne wskazanie osób, których kod należy kojarzyć jako błędogenny. W analogiczny sposób można by poczynić wnioski odwrotne i wytypo­ wać koderów, do których pracy nie trzeba podchodzić ze szczególną ostrożnością. Błąd — w niniejszej książce termin „błąd” odnosi się do ostatecznego zachowania apli­ kacji, które jest niezgodne, sprzeczne lub niepełne w porównaniu z zapisem w wymaga­ niach. Reakcja programu jest odzwierciedleniem instrukcji kodu, która w danym mo­ mencie została wykonana. De facto niepożądane zachowanie systemu jest skutkiem (objawem) błędnie wykonanej implementacji, tj. wady kodu. Niemniej jednak posta­ rajmy się mówić o błędzie jako skutku, którego przyczyna tkwi w instrukcjach kodu.

12

Testowanie oprogramowania. Podręcznik dla początkujących

Błąd krytyczny — często spotykamy się z określeniem „błąd krytyczny” w odniesieniu do zachowania systemu. W zależności od kontekstu i kultury pracy określenie to może przybierać nieco inne znaczenie, a w zasadzie błąd może mieć nieco inną wagę w sto­ sunku do porównywalnych sytuacji. Wynika to z różnic w specyfikach systemów, roli, jaką odgrywają, i wrażliwości klienta na problemy z oprogramowaniem. Niemniej jed­ nak za błąd krytyczny należy uznać niepożądane zachowanie systemu, które realnie wpływa na funkcjonowanie procesów biznesowych. Ów wpływ może objawić się poprzez konieczność wyłączenia jakiegoś modułu, gdyż nie może on dalej stanowić wsparcia dla użytkowników, lub jako skutek błędnego wykonania jakiegoś procesu biznesowego, np. błędnie wyliczono kwoty faktur VAT za usługi telekomunikacyjne. Jeżeli system błędnie zaksięguje odsetki od niezapłaconych faktur VAT, to jest to błąd krytyczny, gdyż usługodawca poniesie realne straty (operacyjne, dotyczące wizerun­ ku). Jeżeli aplikacja wygeneruje billingi jedynie dla klientów, którzy nie przekroczyli 5000 połączeń w okresie rozliczeniowym, to również jest to błąd krytyczny. Nato­ miast w przypadku, kiedy jakiś raport błędnie podaje sumę połączeń (np. minuty), nie należy klasyfikować tego zdarzenia jako krytyczne. Stosunkowo często środki masowe­ go przekazu informują o problemach z dostępem do środków przez klientów jakiegoś banku — to jest błąd krytyczny. Natomiast błędne wyświetlanie waluty rachunku (bez wpływu na zdarzenia księgowe), w jakiej faktycznie jest prowadzony rachunek, nie jest sytuacją krytyczną; nawiasem mówiąc, całkiem przyjemnie nagle zobaczyć 5000,00 euro zamiast 5000,00 zł. Błąd blokujący — to pojęcie podnoszone jest głównie w procesie testowym jako sytuacja, która uniemożliwia kontynuowanie testów danego obszaru. Załóżmy, że w systemie istnieje wada uniemożliwiająca mu poprawną kooperację z usługą sieciową, której wywołanie jest niezbędne do przejścia do kolejnych kroków operacji biznesowej. Jest to błąd blokujący, gdyż nie jesteśmy w stanie zweryfikować niczego, co kryje się po­ niżej tego etapu (wywołania funkcji WS). Tego rodzaju błędy powinny być popra­ wiane z bardzo wysokim priorytetem, gdyż blokują testy i jednocześnie nie zatrzymują upływu czasu (termin dostawy). Trywialność wykrycia błędu — do jednych z najbardziej przykrych sytuacji w pracy testera należy zaliczyć „wpadki”, które niosą poważne konsekwencje, a istota (błąd) owego stanu rzeczy była łatwa do wykrycia w fazie testów. Niestety bywa tak, że coś umknie uwadze testera i ujawni się dopiero w środowisku produkcyjnym, niosąc za sobą wymierne problemy. Sytuację należy również odwrócić i pochylić się nad analizą ewentualnych „ciężkich błędów”, które ujawniają się w bardzo wyrafinowanych i skom­ plikowanych sytuacjach. Niezależnie od tego, z jakim typem błędu przyszło nam się borykać (pod względem wysiłku wykrycia), należy poddać gruntownej analizie zaist­ niałą sytuację w celu nauki i udoskonalenia testów (uszczelnienie). Debugowanie (ang. debugging — odrobaczanie) jest to proces analizowania, wyszu­ kiwania i eliminacji wad w oprogramowaniu poprzez kontrolowane (krokowe) wyko­ nywanie kodu. Jest to czynność wykonywana przez programistów. Przypadek testowy to zestaw początkowych i końcowych warunków wykonania okre­ ślonej ścieżki w programie, realizacja owej ścieżki oraz zapis wyniku w celu zweryfiko­ wania zachowania aplikacji (fragmentu), tj. sprawdzenia zgodności z zapisanymi wy­ maganiami. Lista przypadków testowych to jak sama nazwa wskazuje dokument, który w sposób skonsolidowany ujmuje powołane przypadki testowe.

Rozdział 1. ♦ Ogólna teoria testowania

13

Scenariusz testów opisuje sekwencje czynności (zdarzenia), jakie należy wykonać w celu przeprowadzenia testu. Wymaganie (specyfikacja) to zestaw warunków i oczekiwań, jakie musi spełniać apli­ kacja. Wymagania wobec programu powinny być ujęte w formalnej dokumentacji. Spe­ cyfikacja powinna być precyzyjna, kompletna i niepozwalająca na zbyt dowolną inter­ pretację przez różne zainteresowane strony. W specyfikacji wymagań oprócz literalnego zapisu oczekiwanego zachowania systemu powinny znaleźć się wszelkie materiały pochodne (wspomagające), takie jak pliki WSDL, opisy plików wymiany da­ nych, spis reguł walidacyjnych dla pól formularzy itp. Dokumentacja to określenie odnoszące się do formalnie wydanych dokumentów, takich jak specyfikacja wymagań, projekt techniczny, scenariusze i przypadki testowe, do­ kumentacja użytkownika, instrukcje wgrania itp. Na podstawie tych materiałów wykona­ na zostanie implementacja, przeprowadzone testy jakościowe i odbiorcze. Dokumen­ tacja będzie również stanowić wsparcie do uruchomienia produkcyjnego aplikacji oraz sporządzenia instrukcji dla użytkownika końcowego. Na potrzeby niniejszej książki to pojęcie będzie miało szerokie i ogólne znaczenie, które odnosi się do formalnych dokumentów. Standardy odnoszące się do testowania oprogramowania Standaryzacja jest wszechobecna w niemal każdym obszarze życia. Testowanie opro­ gramowania również ujęte zostało w szeregu upublicznionych standardów. Do najpo­ pularniejszych z nich należy zaliczyć: ♦ IEEE 829-1998 (IEEE Standard for Software Test Documentation): http://standards.ieee.org/findstds/standard/829-1998.html ♦ BS 7925-2 Software Component Testing Standard: http://www.testingstandards.co.uk/bs_7925-2. htm ♦ IEEE 1012-2012 (IEEE Standard for System and Software Verification and Validation): https://standards.ieee.org/findstds/standard/1012-2012.html

IEEE (ang. Institute o f Electrical and Electronics Engineers) to organizacja skupiająca inżynierów elektryków i elektroników — Instytut Inżynierów Elektryków i Elektroników: http://www.ieee.org/, http://www.ieee.pl/.

1.1. Techniki testowania Tester ma do dyspozycji dwie podstawowe techniki testowania: ♦ metodę czarnej skrzynki (ang. Black Box), ♦ metodę białej skrzynki (ang. White Box).

Metoda czarnej skrzynki nie przewiduje zgłębiania wewnętrznej struktury programu. Skupia się na weryfikacji założeń funkcjonalnych bez odniesienia do kodu aplikacji.

14

Testowanie oprogramowania. Podręcznik dla początkujących

Rysunek 1.1 obrazuje ideę metody czarnoskrzynkowej. Testy oparte na tej metodzie polegają na uruchamianiu programu w warunkach maksymalnie zbliżonych do natural­ nych (rzeczywista obsługa systemu). Zaletą metody czarnej skrzynki jest brak wymogu posiadania umiejętności analizy i czytania kodu. Kontroler jakości posługuje się jedy­ nie udostępnionym interfejsem lub zewnętrznym klientem, np. SoapUI w przypadku testów funkcji web service. Tester nie zgłębia, w jaki sposób kod aplikacji realizuje założenia funkcjonalne. Tester uruchamia weryfikowaną opcję programu, definiuje pa­ rametry wejściowe i sprawdza wynik wykonanej akcji. Wadą tej metody jest brak gwa­ rancji, że wszystkie instrukcje kodu zostaną przetestowane (wykonane). W przypad­ ku wystąpienia błędu jego przyczyna nie jest znana. Testy metodą czarnoskrzynkową powinny być uzupełnione testami opartymi na technice białej skrzynki. Rysunek 1.1. Technika czamoskrzynhowa W E J Ś C IE

Metoda testów białej skrzynki opiera się na analizie struktury kodu. Wymaga ona podstawowej znajomości zasad programowania (czytanie i rozumienie kodu) oraz zasto­ sowanej technologii, np. Javy. Dostęp do źródła kodu pomaga w ustaleniu typu i zakre­ su danych wejściowych potrzebnych do przeprowadzenia testu. Ponadto w momencie wystąpienia błędu jawność kodu umożliwia zidentyfikowanie problemu oraz ustalenie miejsca jego występowania. Rysunek 1.2 przedstawia ideę techniki białoskrzynkowej. Główną wartością testów białej skrzynki jest możliwość zmierzenia (oceny) pokrycia testami analizowanego obszaru aplikacji. Jednak jest to równocześnie wadą omawia­ nej metody, gdyż tester projektując i/lub wykonując testy, może ulec podprogowej sugestii i zaaranżować przypadek „pod kod”, a nie względem wymagania funkcjonalne­ go. Zważywszy na powyższe zagrożenie, testy wykonywane metodą białej skrzynki powinny być wykonywane po testach funkcjonalnych. Testy białej skrzynki powinny wykazać luki w pokryciu (wykonaniu) kodu przez scenariusze testowe. Wyniki takich testów po analizie posłużą do udoskonalenia testów (przypadków testowych), tak aby zwiększyć staranność pokrycia testami weryfikowanych struktur. Rysunek 1.2. Technika bialoskrzynkowa W E J Ś C IE

Wartością testów wykonywanych metodą białej skrzynki jest możliwość wychwyce­ nia fragmentów kodu, które potencjalnie mogą obniżyć wydajność. Dokonać ozna­ czenia „podejrzanego” kodu może tester, który posiada podstawowe kompetencje

Rozdział 1. ♦ Ogólna teoria testowania

15

programistyczne, zna właściwości i cechy zastosowanej technologii oraz umie przeło­ żyć zapis kodu na docelowy skutek jego uruchomienia. Nie, nie trzeba wykazywać się w pełni umiejętnościami przypisywanymi do stanowiska programisty, choć znajomość zasad programowania jest podstawą pozwalającą wspierać optymalizację kodu w trakcie wykonywania testów. Wydatnym przykładem jest instrukcja IF, której warunek lo­ giczny składa się z dwóch członów (listing 1.1, listing 1.2). Jeżeli w podanym przykła­ dzie zostanie spełniony pierwszy warunek instrukcji (ten skomplikowany), to drugi jest automatycznie pomijany (ten prostszy). Przekładając algorytm na język naturalny: jeżeli pracownik nie był na zwolnieniu lekarskim (zwLekarskie=0), to weryfikujemy, czy jego pensja nie przekracza 7000. Jeżeli nie przekracza, to otrzymuje on premię w wy­ sokości 1500, w innym przypadku nie otrzymuje dodatku. Jeśli pracownik przebywał na zwolnieniu lekarskim (1), nie jest już badany warunek wysokości pensji. Z bizne­ sowego punktu widzenia kod wygląda jak najbardziej dobrze. Problem polega na tym, że parametr wysokości pensji (kwotaPensja) pobierany jest z interfejsu użytkownika (GUI), tj. pani kadrowa wpisuje kwotę ręcznie, natomiast informacja o zwolnieniach lekarskich pobierana jest z bazy danych (przykład nie odwzorowuje tego w kodzie). Testy funkcjonalne potwierdziły, że pole obsługujące wynagrodzenie zawsze musi być uzupełnione — zatem jest to pewnik. Przebywanie na zwolnieniu lekarskim jest zda­ rzeniem losowym. Gdy analizuje się przedstawiony kod (listing 1.2), nasuwa się kon­ cepcja zamienienia miejscami warunku A z B (listing 1.3) — tak aby w pierwszej ko­ lejności program sprawdzał wysokość pensji, a dopiero później starał się potwierdzić brak absencji w pracy. Takowe rozwiązanie zoptymalizuje kod pod względem wydajno­ ściowym, gdyż zagwarantuje wykonywanie „kosztownego kodu” (łączenie się z bazą danych oraz wykonywanie zapytania) w sytuacjach tego wymagających. Takie podej­ ście oszczędza zasoby z uwagi na to, że zezwala na wykonanie kosztownego kodu jedy­ nie w odpowiedzi na rzeczywiste zapotrzebowanie biznesowe, a nie zawsze, tak jak to miało miejsce przy pierwszej propozycji rozwiązania (listing 1.2). Listing 1.1. Pseudokod opisujący instrukcję IF z warunkiem logicznym && języka Java i f ( A_zwLe kar s ki e=t r ue && B_kwotaPensj a) pr e mi a =t a k ;

{

} else { pr e mi a =ni e ; }

Listing 1.2. Instrukcja IF z warunkiem logicznym && w Javie. Weryfikacja pensji na drugiej pozycji package p l . t e s t o w a n i e ; p u b l ic c l a s s Opt ymal izacj a { s t a t i c i n t zwLekar s ki e = 1; / / 0 - brak zwolnienia, 1 - zw olnienie s t a t i c i n t kwot aPens j a = 5000; s t a t i c i n t kwot aPremi a; p u b l i c s t a t i c voi d m a i n ( S t r i n g [ ]

args)

{

i f ( zwLe kar s ki e == 0 && kwot aPen s j a < 7000) { kwot aPremi a = 1500; S y s t e m . o u t . p r i n t l n ( " P r z y z n a n o pr emi ę w wys okoś ci : " + kwot aPr emi a) ; }

16

Testowanie oprogramowania. Podręcznik dla początkujących

else { kwot aPremi a = 0; S y s t e m . o u t . p r i n t l n ( " P r e m i a n i e z o s t a ł a p r z y z n a n a z powodu z b y t wys okiej ^ p e n s j i i / l u b zwolnienia lekar ski ego ") ; } } }

Listing 1.3. Instrukcja IF z warunkiem logicznym && w Javie. Weryfikacja zwolnienia lekarskiego na drugiej pozycji package p l . t e s t o w a n i e ; p u b l i c c l a s s Op t y ma l i z a c j a 2 { s t a t i c i n t zwLekar s ki e = 0; / / 0 - brak zwolnienia, 1 - zw olnienie s t a t i c i n t kwot aPens j a = 5000; s t a t i c i n t kwot aPremi a; p u b l i c s t a t i c voi d m a i n ( S t r i n g [ ]

args)

{

i f ( k wot a P e ns j a < 7000 && zwLekar s ki e == 0) { kwot aPremi a = 1500; S y s t e m . o u t . p r i n t l n ( " P r z y z n a n o pr emi ę w wys okoś ci : " + kwot aPr emi a) ; } else { kwot aPremi a = 0; S y s t e m . o u t . p r i n t l n ( " P r e m i a n i e z o s t a ł a p r z y z n a n a z powodu z b y t wys okiej ^ p e n s j i i / l u b zwolnienia lekar ski ego ") ; } } }

Instrukcje zamieszczone w powyższych przykładach są mocno abstrakcyjne. Niemniej jednak opisują jedną z elementarnych sytuacji, w której tester powinien zachować czujność i otwarcie powiedzieć o swoich obawach. Zwykle testerzy nie posiadają kom­ petencji regularnego programisty, zatem często podnoszone przez nich kwestie zwią­ zane z optymalizacją kodu mogą nie mieć odzwierciedlenia w realnym zagrożeniu dla aplikacji. Jednakże nie powinno mieć to negatywnego wpływu na pracę np. poprzez zaniechanie zgłoszenia swoich podejrzeń w obawie przed „kompromitacją”. Koszt obsługi kilku czy kilkunastu nie do końca zasadnych zgłoszeń jest niewspółmiernie niski w stosunku do kosztów obsługi pojedynczego incydentu w środowisku produk­ cyjnym. Testerowi nie wolno „przymykać oka” w obawie przed konfrontacją z pro­ gramistą, projektantem lub projektantem i analitykiem. Jawność kodu w procesie testowania aplikacji stwarza warunki do weryfikacji, czy programista stosuje się do tak zwanych dobrych zasad programowania lub wręcz czy przestrzega ogólnie narzuconych wytycznych. Pożądaną praktyką w programowaniu jest oddzielenie logiki systemu od warstwy prezentacji. Testy wykonywane metodą białej skrzynki umożliwiają ocenę, czy taka zasada jest respektowana. Równie istotne jest przestrzeganie przyjętej konwencji nazewnictwa np. zmiennych, stałych, klas,

Rozdział 1. ♦ Ogólna teoria testowania

17

pakietów etc. Implementacja kodu według wspólnej konwencji jest niezmiernie istotna z punktu widzenia zarządzania projektem i/lub całym przedsiębiorstwem. Kod źródłowy nie jest trwale związany z jego autorem. Unifikacja ułatwia podjęcie pracy innemu programiście, który uprzednio nie uczestniczył w danej implementacji, a jed­ nocześnie ma doświadczenie w innych projektach tej samej korporacji. Programista, który powołał określoną funkcjonalność, może zmienić pracę, skorzystać z urlopu wypoczynkowego, zachorować lub ulec innemu zdarzeniu losowemu, ale kod przez nie­ go napisany nadal pozostaje w repozytorium i w razie konieczności musi być rozwi­ jany i serwisowany. Standaryzacja pracy jest wymogiem koniecznym w celu zacho­ wania ciągłości obsługi kodu.

1.2. Miara jakości oprogramowania Oprogramowanie poddawane jest testowaniu w celu zminimalizowania ryzyka wystą­ pienia błędów w środowisku produkcyjnym. Jakość to termin opisujący istotne cechy, które wyróżniają produkt w sposób szczególny — zarówno negatywny, jak i pozy­ tywny. Określenie jakości produktu w oparciu o relacje opisowe nie przynosi spodzie­ wanych rezultatów, gdyż treść przekazu zależna jest od podmiotu sporządzającego (poznawczego). Subiektywne podejście do oceny wartości oprogramowania stanowi przeszkodę w uzyskaniu rzeczywistej oceny stanu produktu. Próby podzielenia się wnioskami z przeprowadzonej analizy mogą okazać się kłopotliwe ze względu na dużą swobodę interpretacji przekazywanych treści. Naturalnym porządkiem rzeczy wydaje się ujęcie poziomu jakości w syntetycznych ramach. Fakty liczbowe stanowią warto­ ściową bazę do przygotowania raportu informującego o bieżącej jakości produktu. Podstawowym parametrem oceny jest kryterium ilościowe opisujące proporcję błę­ dów wykrytych w fazie produkcji oprogramowania do liczby zgłoszeń ujawnionych w środowisku zewnętrznym (po zakończeniu procesu produkcji w fazie odbiorczej). Za klienta ostatecznego należy uważać docelowego użytkownika systemu. Zastrzec należy, że odbiorcą oprogramowania nie musi być zupełnie niezależny klient zewnętrzny. Software produkowany jest również na potrzeby własne podmiotu lub dla jednostek o powiązanym kapitale. W tym miejscu należy poszerzyć wiedzę zarówno w tematyce klienta zewnętrznego, jak i wewnętrznego w oparciu o niezależne i dedykowane pu­ blikacje. Ów wskaźnik (ilościowy) nie wystarcza do odwzorowania rzeczywistego stanu aplikacji. Niemniej jednak uwzględniany jest w procesie opiniowania i powi­ nien mieć ustaloną wartość graniczną, po której przekroczeniu inicjowany jest sygnał ostrzegawczy. Powyższy wskaźnik wymaga szczególnej uwagi w momencie interpreta­ cji. Nie rozróżnia on rangi błędów, jedynie konfrontuje ze sobą ich liczbę. Błędy kry­ tyczne traktowane są na równi z usterkami oraz z innymi mniej istotnymi problema­ mi. Rysunek 1.3 prezentuje porównanie ilościowe błędów wykrytych w środowisku testowym producenta w stosunku do błędów ujawnionych u klienta. Kryterium ilościowe powinno być wspierane parametrem określającym zbiorczy cię­ żar merytoryczny błędów. Waga 100 dużych błędów nie odpowiada takiej samej ilo­ ści zgłoszonych usterek, np. literówek, drobnych niedociągnięć graficznych itp.

18

Testowanie oprogramowania. Podręcznik dla początkujących

Rysunek 1.3. Porównanie ilościowe zgłoszeń własnych oraz zewnętrznych

Porów nanie ilościowe zgłoszonych b łędó w 140

Trzecim parametrem są informacje zwrotne płynące bezpośrednio od użytkowników systemu. Opinie klientów należy zestawić z zebraną statystyką pozostałych parame­ trów oprogramowania. Zabieg ten pozwoli na uwiarygodnienie trafności pomiaru (pokrycie liczb zgodne z powszechnym mniemaniem) lub zasygnalizuje konieczność zmodyfikowania wskaźników. W sytuacji kiedy przyjęte kryteria rozmijają się z opi­ nią klienta, należy zmodyfikować zasady pomiaru, np. zmieniając progi lub dodając nowe wskaźniki. Niepokojące wartości pewnych parametrów nie muszą oznaczać po­ ważnych problemów z jakością produktu. Produkcja oprogramowania jest procesem skomplikowanym i zależnym od wielu czynników. Niestandardowe okoliczności mogą w mniejszym lub większym zakresie uzasadniać odstępstwo od reguł. Elementem niezmiernie istotnym jest określenie (wyliczenie z danych popartych ana­ lizą) współczynnika powagi (skutków) błędów do poziomu skomplikowania sytuacji ich wystąpienia. Nadmieniłem na uprzednich kartach książki, że bywają błędy o du­ żym ciężarze w skutkach, a trywialnej sytuacji ich występowania. Duży odsetek błędów potencjalnie błahych do wykrycia, które ujawnione zostały przez klienta, nie świad­ czy dobrze o jakości oprogramowania. Nieco inaczej należy interpretować błędy, które znajdują podbudowę w wyrafinowanych i trudno osiągalnych scenariuszach dla testera u wytwórcy. Niepodważalnie istnieją podmioty, które dysponują wystarczającą siłą i środkami, aby realizować produkcję oprogramowania na własne potrzeby we własnym zakresie. Wydatnym przykładem mogą się okazać korporacje wytwarzające urządzenia elektro­ niczne, tj. tablety, smartfony, telewizory, laptopy itp. Niemniej jednak z punktu wi­ dzenia oceny jakości oprogramowania niewiele to zmienia. Przymykając oko na niu­ anse i detale związane z funkcjonowaniem poszczególnych podmiotów, można uznać, że powyżej przytoczony ogólny model oceny jakości wytwarzanego oprogramowania nosi cechy uniwersalności. Zaiste realizacja projektu na potrzeby grupy kapitałowej lub wręcz w ramach tego samego podmiotu może z natury wydawać się łatwiejsza. Niemniej jednak nie jest to tożsame z dewaluacją ryzyka dla obu ze stron, tj. klienta

Rozdział 1. ♦ Ogólna teoria testowania

19

i zleceniobiorcy. Wprawdzie projekt może przepływać przez jednostki związane ka­ pitałowo, jednak zawsze występuje ktoś w roli zleceniodawcy i realizatora. Wszakże należy pamiętać, że nawet projekty podejmowane wewnętrznie obciążone są kosztami operacyjnymi, które prędzej czy później muszą zostać rozliczone. Załóżmy, że produ­ kujemy oprogramowanie do nowej linii telewizorów. Załamanie terminu zakończenia prac wpłynie realnie na harmonogram wprowadzenia do sprzedaży gotowego produktu (telewizory). Myślenie typu „nic się nie stanie, jakoś się dogadamy wewnętrznie” jest zgubne i błędne. Dlatego system nadzoru nad jakością oraz efektami pracy jest równie istotny jak w realizacjach kontraktu dla klienta zupełnie niepowiązanego z podmio­ tem wytwarzającym. Notabene, jak już wcześniej wspominałem, całościowe parame­ try jakości składają się z wielu pomniejszych, które z kolei mogą odnosić się do pracy poszczególnych osób lub zespołów. Wykrycie i zidentyfikowanie ewentualnych źró­ deł pogorszenia jakości ma kluczowe znaczenie dla udoskonalenia procesu wytwórczego oraz dojrzałości korporacji jako całości. Zgodnie z powiedzeniem co kraj to obyczaj różne firmy mogą odmiennie podchodzić do problematyki jakości. Pewne jest jedno: bez nadzoru nad jakością i harmonogramem żaden projekt nie ma prawa zakończyć się sukcesem. Miałem okazję rozmawiać z programistami realizującymi projekty dla bardzo dużej korporacji. Programowali oni w parach. Dwóch programistów przy jednym komputerze. Jeden „pisał”, drugi weryfikował kod, uczył się i zgłaszał wszelkie wątpliwości meryto­ ryczne. Ów minizespół cyklicznie zamieniał się rolami, tzn. obserwator z koderem. Drugą arcyciekawą praktyką było odsyłanie wytworzonego kodu przed jego formalną publikacją do programisty o wyższych kompetencjach, który oceniał napisane in­ strukcje, wnosił uwagi i poprawki, a następnie odsyłał materiał do autora. Takie roz­ wiązanie wnosi wiele do procesu edukacji i kształtowania pracy programistów. Z pewno­ ścią w dłuższej perspektywie ostateczna jakość kodu zostanie znacznie zwiększona. Niewątpliwie powyższe dwie metody mogą istotnie przyczynić się do efektywności pracy i niezawodności wytwarzanego kodu. W takich okolicznościach można by się spodziewać, że testerzy funkcjonalni nie będą często borykać się z błędami oczywi­ stymi i krytycznymi. Cóż, programista niejako „poprawiający kod po kolegach” jest pierwszym testerem i to on ma świadomość ilości, wagi i typów błędów popełnianych przez zespół programistów. W tym miejscu również można zastosować markery jakości. Metodologii (praktycznych) badania i zapewnienia jakości oprogramowania jest tak wiele, jak wiele jest podmiotów je wytwarzaj ących. Pewne ogólne przesłanki znajdą zastosowanie w większości podmiotów. Niemniej jednak warto pamiętać, że wypadkowa polityka może znacznie się różnić pomiędzy różnymi firmami. Teoria teorią, a praktyka praktyką. Obecne czasy wykluczają opieranie się podczas rekrutacji pracowników tylko i wyłącznie na dokumentach potwierdzających kwalifi­ kacje. Elementem wiodącym są konkretne umiejętności. Rzecz jasna pożądane dla pra­ codawcy. Zatem nie rekomenduje się wchłaniania niezliczonej ilości informacji, które zwykle po kilkunastu miesiącach mogą okazać się nieaktualne. Istotne jest posiadanie wiedzy elementarnej, lecz aktualnej, która pozwoli na szybkie dostosowanie się do specyfiki pacy i wymogów pracodawcy. W ICT kluczem do sukcesu jest szybka asy­ milacja, aktualna i wiarygodna wiedza, która stanowi bazę do dalszego samorozwoju. Jeżeli nie wspomniałem jeszcze o aktualnym trendzie w edukacji, to zrobię to teraz.

20

Testowanie oprogramowania. Podręcznik dla początkujących

System szkolnictwa nie jest w stanie „wlać” całości niezbędnej wiedzy „do głowy studenta”. Co więcej, nie jest w stanie jej zweryfikować i wyegzekwować. Między innymi z tego powodu większy nacisk kładzie się na nauczenie jednostki, jak należy się samodzielnie uczyć i rozwijać, niż na zapamiętywanie tysięcy wersów z książek, których treści przestaną być aktualne, zanim słuchacz ukończy szkołę (przynajmniej w informatyce). Taką też rolę założyłem dla niniejszej publikacji. Ma ona otworzyć drogę Czytelnikowi do dalszego samorozwoju w roli testera oprogramowania. Jak to się ma do oceny jakości? Przyjęty model weryfikacji efektów pracy może na pierwszy rzut oka okazać się krzywdzący, niezrozumiały, wadliwy etc. Z punktu wi­ dzenia jednostki może pojawić się nawet poczucie zagrożenia i istnienia narzędzia re­ presji. Sęk w tym, aby znaleźć w owym systemie elementy, które mogą potencjalnie chronić nasze interesy, np. raportować problemy dyskusyjne, które później może po­ ruszyć klient w fazie odbioru oprogramowania. Jak to się mówi: szklanka jest do po­ łowy pełna lub do połowy pusta. Kluczem jest zdolność do przystosowania się, czyli umiejętność posłużenia się nauką „jak się samodzielnie uczyć”. Powyżej pochyliliśmy się nad podstawowymi markerami, za pomocą których można opisywać ostateczną jakość oprogramowania. Pozostaje jeszcze kwestia interpretacji wyniku oraz metody zbierania danych. Satysfakcję użytkownika końcowego można mierzyć poprzez ankiety. Niezawodność można określać jako czas bezproblemowej pra­ cy weryfikowanego modułu. Efektywność pracy można również mierzyć poprzez ze­ stawienie ilości błędów w stosunku do napisanych linii kodu. Termin jakość oprogramowania można spróbować zamknąć w ramach kilku jego atry­ butów: ♦ funkcjonalność (poziom zaspokojenia potrzeb klienta), ♦ niezawodność, ♦ przenośność i łatwość instalacji, ♦ łatwość utrzymania, ♦ wydajność, ♦ ergonomia i łatwość obsługi (ang. usability), ♦ użyteczność dokumentacji,

♦ podatność na rozwój. Powyżej opisywane markery (punkty kontroli oprogramowania) powinny odwzoro­ wywać rzeczywisty stan aplikacji, tzn. stanowić liczbowy trzon dla opisowych atry­ butów. Duża liczba nierozwiązanych problemów wydajnościowych, rzecz jasna, obniża atrybut wydajności. Analogicznie często raportowane błędy dla tego samego obszaru aplikacji świadczą negatywnie o niezawodności oprogramowania. Zwykle pomiędzy producentem a klientem oprogramowania zostaje zawiązana umowa, która określa parametry krytyczne oraz pożądane cechy, jakie musi posiadać system. Ostateczna polityka zarządzania jakością oraz parametry progowe, które zadowalają klienta, ustalane są w formie negocjacji. Dlatego można się spodziewać różnic w po-

Rozdział 1. ♦ Ogólna teoria testowania

21

dejściu do aspektów jakości przy realizacji kolejnych i niezależnych kontraktów. Jed­ nemu klientowi może znacznie bardziej zależeć na niezawodności, a drugi dopuszcza krótkotrwałe przerwy w pracy na rzecz polepszenia innych parametrów, np. atrakcyj­ ności GUI. Wskaźniki odnoszące się do produktu mogą i powinny być wykorzystane do określenia: ♦ ogólnego stanu produktu, ♦ efektywności działu kontroli jakości, ♦ skuteczności testera, ♦ sprawności programisty, ♦ jakości zarządzania projektem (w tym analizy wymagań biznesowych). Rozważmy hipotetyczny projekt, który przewiduje 22 dni testów. Liczba osób zaan­ gażowanych nie jest istotna. Wskaźnik ilościowy został ustalony w proporcji 5:1. Oznacza to, że producent dopuszcza maksymalną liczbę błędów zgłoszonych w fazie odbiorczej (testy u klienta) na poziomie 20% wszystkich zarejestrowanych błędów w trakcie testów jakościowych (u producenta). Projekt zakończył się rezultatem 119:21, co daje wynik 15% (rysunki 1.3 i 1.4). Zakładając, że w puli 21 błędów zgłoszonych przez klienta nie ma problemów krytycznych i/lub o znaczącym ciężarze merytorycz­ nym, można przyjąć, że projekt zakończył się sukcesem (jeżeli współczynnik nie prze­ kracza przyjętego założenia). Rysunek 1.4. Procentowy rozkład zgłoszeń wewnętrznych i zewnętrznych

Procentowy rozkład zgłoszeń ■ Producent

■ Klient

Monitorowanie jakości w trakcie trwania projektu testowego jest kluczowym ele­ mentem pozwalającym na bieżącą ocenę sytuacji. Skutecznym narzędziem może okazać się wykres obrazujący ilość błędów zgłaszanych w poszczególnych dniach testowa­ nia. Rysunek 1.5 przedstawia wykres projektu testowego trwającego 22 dni robocze (mianem projektu testowego określa się jeden z etapów procesu wytwarzania opro­ gramowania, w którym weryfikowana jest jakość dostarczonego produktu). Pierwsze sześć dni wskazuje na tendencję rosnącą. Oznacza to, że testerzy wykazują się aktywno­ ścią, a aplikacja i środowisko nie blokują postępu prac. Pomiędzy czwartym a jedena­ stym dniem wpłynęło najwięcej błędów. Dwunasty dzień rozpoczyna trend malejący,

22

Testowanie oprogramowania. Podręcznik dla początkujących

Przebieg rejestracji błęd ó w 14

10

1

2

3

5

6

7

8

10

11

12

13

14

15

16

17

18

19

20

21

22

Rysunek 1.5. Przykładowy przebieg rejestracji błędów w trakcie trwania projektu testowego który w kolejnych dniach zbliża się ku zerowej wartości. Mniej więcej w okolicy sie­ demnastego dnia można wysnuć wniosek, że testerzy nie ujawniają błędów przy stan­ dardowej obsłudze systemu i przeszli do fazy bardziej złożonych oraz wyrafinowanych testów („szukają błędów”). W kolejnym dniu został zarejestrowany pojedynczy błąd, jednak mimo to sytuacja nadal jest stabilna. Kolejne dni testów potwierdzają, że ja ­ kość aplikacji jest na dobrym poziomie. Rysunek 1.6 odnosi się do projektu testowego, który z dużym prawdopodobieństwem nie zakończy się w założonym terminie. Tendencja w drugiej połowie harmonogramu wskazuje, że aplikacja w dalszym ciągu zawiera błędy, które są ujawniane w kolej­ nych dniach testów na mniej więcej równym poziomie. Nie widać trwałego spadku zgłoszeń. Zatem z dużym prawdopodobieństwem w nadmiarowym czasie testów mogą wystąpić dodatkowe problemy. Zakończenie prac po upływie założonych 22 dni ro­ boczych jest wielce ryzykowne. Interpretacja wykresu sugeruje kontynuowanie testów w celu poprawienia jakości produktu. Wiąże się to z przekroczeniem planowanego terminu zamknięcia projektu testowego. Analiza wykresu wskazuje jeszcze jeden pro­ blem, który miał miejsce w początkowej fazie testów. Pierwsze trzy dni nie przyniosły dostatecznych efektów w postaci liczby zgłoszonych błędów. Ów fakt może sugero­ wać, że na etapie rozpoczęcia testów wystąpiły problemy z uruchomieniem aplikacji (środowisko) lub zawierała ona błędy krytyczne, które zablokowały postęp prac. Sfor­ mułowane podejrzenie nie musi znaleźć odzwierciedlenia w rzeczywistości, jednakże powinno być zweryfikowane. Wykres z rysunku 1.7 przedstawia sytuację, która wymaga szczególnej uwagi i szyb­ kiej reakcji. Dzień czwarty i piąty nie przyniosły żadnych nowych zgłoszeń, mimo że spodziewany był trend rosnący. Oznaczać to może, że zespół kontroli jakości utracił możliwość kontynuowania testów ze względu na błędy blokujące (brak możliwości przejścia do dalszych obszarów aplikacji) lub kłopoty środowiska pracy. Gwałtowny spadek charakterystyki, a następnie równie szybki wzrost stanowi sytuację niepokojącą.

Rozdział 1. ♦ Ogólna teoria testowania

23

Przebieg rejestracji błędów 10 S

\ \

1

2

4

3

7

6

8

9

10

11

12

13

14

\

15

16

\s

\

17

18 19

20 21

22

Rysunek 1.6. Przykładowy przebieg rejestracji błędów w trakcie trwania projektu testowego

F*n tek>ieg re je stac ji bł ę dówł IR IG /

14

/

12 10 8

"s

/

js

II

b

\

4

\

2

V

\

0 1

2

3

4

G

7

8

9

IG

11

12

13

14

15

IG

17

18

19

20

21

22

Rysunek 1.7. Przykładowy przebieg rejestracji błędów w trakcie trwania projektu testowego W teorii testowanie oprogramowania jest procesem nieskończonym. Aspekt praktyczny wspierany przez względy ekonomiczne nakazuje wyznaczyć moment, w którym testy mogą być zaprzestane. Zakończenie testów możliwe jest po spełnieniu przez system wszystkich punktów kontrolnych. Oprogramowanie powinno być oficjalnie wydane w przekonaniu, że spełnia pokładane w nim oczekiwania oraz będzie funkcjonowało w sposób satysfakcjonujący w środowisku produkcyjnym.

1.3. Środowisko testowe i produkcyjne Środowisko testów to ogół elementów infrastruktury technicznej oraz modułów opro­ gramowania, które stanowią podbudowę do uruchomienia właściwej aplikacji podda­ wanej testowaniu. Zdolność do wykonania testów w wymaganym zakresie bezpośrednio zależy od stanu i możliwości zaplecza. Środowisko testowe powinno być w optymalny sposób zbliżone do produkcyjnych warunków funkcjonowania systemu (aplikacji). Odwzorowanie środowiska w relacji 1:1 jest w praktyce bardzo trudne, kosztowne i na ogół niepotrzebne. Kluczową kwestią dla procesu testowania jest możliwość urucho­ mienia wszystkich funkcjonalności (opcji) systemu.

24

Testowanie oprogramowania. Podręcznik dla początkujących

Środowisko testowe powinno być odizolowane i niezależne od wpływu programistów, którzy często nie mogą oprzeć się pokusie pracy w nim. Dostęp do tego środowiska jest bardzo atrakcyjny dla programistów ze względu na to, że ich własne zasoby są zwykle dużo bardziej ubogie w dane oraz posiadają luki funkcjonalne. Ponadto analiza i naprawa błędu na „żywym organizmie” w realnych okolicznościach jest dużo łatwiej­ sza. Dobro wspólne wymaga, aby wspierać pracę programistów, jednak nie oznacza to bezwarunkowej zgody na penetrację środowiska testów. Pożądane cechy środowiska testów: ♦ stabilność i ciągłość pracy, ♦ zaufanie do gromadzonych danych, ♦ zaufanie do stanu kodu, ♦ niezależność od środowiska deweloperskiego, ♦ optymalnie pełne pod względem uruchamiania funkcjonalności. Wszelkie niedomagania środowiska potencjalnie mogą wpłynąć na obniżenie jakości produktu końcowego. Zespół kontroli jakości w celu przeprowadzenia efektywnych testów powinien mieć zagwarantowany stosowny komfort pracy. Podstawowym wy­ mogiem jest utrzymanie ciągłości pracy środowiska oraz jego stabilności. Nierzadko przygotowanie testu trwa kilkakrotnie dłużej niż jego wykonanie. Środowisko musi pra­ cować w sposób przewidywalny, bez nieplanowanych przerw i anomalii. Wykonując określone zadania, testerzy równolegle gromadzą dane z zamierzeniem ich powtórne­ go wykorzystania w przyszłości. Niespodziewane zniszczenie lub utrata tak wypracowa­ nego zasobu może w znacznym stopniu cofnąć poziom zaawansowania projektu testo­ wego lub odwlec w czasie rozpoczęcie nowego przedsięwzięcia. Tester musi mieć pewność, że przygotowane środowisko do testów zastanie w dniu następnym w stanie nienaruszonym. Każda ingerencja programisty w środowisko testowe niesie ze sobą ryzyko potrakto­ wania wadliwego działania systemu będącego wynikiem chwilowej modyfikacji kodu jako błąd. Błąd, który w normalnych warunkach nie istnieje. Dodatkowym utrudnieniem może okazać się konieczność wyłączenia (zablokowania) części środowiska z zadań testowych na potrzeby deweloperskie. Istotne jest wypracowanie poczucia odpowie­ dzialności koderów za stan środowiska testów, tj. należy wymusić nawyk „sprzątania po sobie”, czyli przywracania kodu do stanu uprzedniego. Pochodną powyższego za­ gadnienia jest konieczność separacji środowisk testowych i deweloperskich. W momen­ cie przejęcia projektu przez dział testów sekcja programistów zwykle rozpoczyna inne zadania, które mogą wchodzić w konflikt z wcześniej przygotowanym materiałem (brak przezroczystości). Przemawia to za rozdzieleniem tych dwóch środowisk. Testy funkcjonalne wymagają, aby każda z opcji była dostępna (działała). Sytuację komplikują obszary, które są zależne od systemów zewnętrznych (kooperują z nimi), do których producent oprogramowania nie ma dostępu. W takich okolicznościach można zastosować symulatory aplikacji obcych w celu zaślepienia obszaru odpowiadają­ cego za komunikację pomiędzy nimi. Eliminując luki o powyższym charakterze, zwięk­ sza się obszar pokrycia aplikacji testami.

Rozdział 1. ♦ Ogólna teoria testowania

25

Termin „środowisko testowe” nie powinien być kojarzony jedynie z deweloperem, gdyż klienci zamawiający oprogramowanie również dysponują takim środowiskiem. Służy ono do wykonywania testów odbiorczych zamawianego oprogramowania, jak również do replikacji błędów zauważonych w środowisku produkcyjnym. Cechą do­ minującą tego środowiska jest potencjał, jakim dysponuje ono w przedmiocie odwzoro­ wania warunków produkcyjnych (docelowego środowiska pracy testowanej aplikacji). Kluczowy wpływ na to ma fakt posiłkowania się kopią danych pochodzących z real­ nie funkcjonującego systemu oraz możliwość integracji pozostałych elementów sys­ temu, które były produkowane przez niezależne firmy. Nie mniej istotne jest obsługi­ wanie systemu zgodnie z obowiązującymi standardami i procedurami. Zespół testów odbiorczych znacznie lepiej rozumie potrzeby i praktyki stosowane przez użytkowników docelowych. Wszystkie powyższe elementy przyczyniają się do utrwalenia przewagi środowiska testowego po stronie klienta nad analogicznym środowiskiem u producenta. Oprogramowanie „pudełkowe” to znaczy takie, w przypadku którego to producent decyduje o jego funkcjonalności i momencie oficjalnego wydania do szerokiej sprze­ daży, nie posiada środowiska testowego po stronie klienta. Podmioty nabywające oprogramowanie zawierzają producentowi, sądząc, że dostarczony produkt jest od­ powiedniej jakości, i od razu wdrażają system jako produkcyjny. Klient nie wykonuje testów odbiorczych w aspekcie procesu produkcji oprogramowania. Wielokrotnie termin „system testowy” odnosi się do aplikacji, które zostały udostępnione do nauki i szkolenia użytkowników. Stosowanie owej definicji w powyższym kontekście nie znajduje uzasadnienia w terminologii kontroli jakości. Oprogramowanie dedykowane dla urządzeń, np. tablety, mapy samochodowe, telefo­ ny etc., powinno również podlegać weryfikacji na fizycznych urządzeniach docelo­ wych. Oczywiście trudno sobie wyobrazić, aby producent aplikacji posiadał pełne spektrum wspieranych urządzeń. Z tego powodu mocno eksploatowane są wszelkie emulatory. Niemniej jednak obsługa programu bezpośrednio na wybranym urządzeniu niesie niezmiernie dużą wartość merytoryczną. W ten sposób unikniemy „smakowania cukierka przez papierek”. Tylko w taki sposób uda nam się poczuć realnie „ducha” aplikacji. Środowisko produkcyjne to ogół komponentów technicznych oraz programowych, które bezpośrednio uczestniczą w obsłudze procesów biznesowych przy pełnej odpo­ wiedzialności za jakość obsługi. Zatem wszelkie modyfikacje głównej infrastruktury powinny być poprzedzone szczegółowymi testami zmienianego elementu. Rozbieżności, jakie mogą wystąpić pomiędzy środowiskiem produkcyjnym a testowym: ♦ różnica w infrastrukturze technicznej (serwery, sieć LAN/WAN), ♦ rozbieżność w architekturze (wielowarstwowość), ♦ niezgodność wersji systemu operacyjnego oraz pozostałego oprogramowania (np. IIS, Oracle, JBoss, Apache etc.), ♦ dysproporcja zarówno w ilości danych, jak również ich różnorodności.

26

Testowanie oprogramowania. Podręcznik dla początkujących

Odrębnym zagadnieniem wymagającym szczególnej uwagi są poprawki wykonywane bezpośrednio w środowisku produkcyjnym. Stawia to zespół testerów w niekomfortowej sytuacji, gdyż 100-procentowe potwierdzenie skuteczności zmiany może okazać się niemożliwe. Pełny obraz efektów funkcjonowania poprawki z reguły można uzyskać dopiero po implementacji jej w środowisku produkcyjnym. W wielu przypadkach pro­ blematycznym obszarem okazują się skrypty SQL lub pliki zmieniające konfigurację serwerów. Z uwagi na rozbieżności w infrastrukturze technicznej lub różny stan da­ nych owe modyfikacje mogą ujawnić problemy o charakterze: ♦ Zmiana nie może zostać w ogóle przetestowana; brak możliwości implementacji w środowisku testowym, np. specyficzna konfiguracja serwera aplikacji. ♦ Zmiana może być wgrana, jednak kontroler jakości nie wychwyci różnicy w działaniu systemu; problemy optymalizacji i wydajności. ♦ Zmiana może być przetestowana z uzyskaniem zauważalnego wyniku, lecz wymaga wcześniejszego spreparowania środowiska: modyfikacji danych z poziomu bazy, zmiany konfiguracji środowiska, przygotowania skryptów wspomagających etc. Bardzo trudno jest wychwycić zauważalne efekty zmian optymalizacyjnych z uwagi na ograniczony wolumen danych lub niewspółmierną możliwość obciążenia systemu. Warunkiem akceptacji takich modyfikacji jest utrzymanie dotychczasowego standardu pracy, czyli niepogorszenie parametrów systemu (wydajność i funkcjonalność) w śro­ dowisku testowym. Spełnienie powyższego kryterium daje podstawy do oczekiwania, że poprawka odegra swoją rolę w środowisku produkcyjnym. Szczególnie interesujące są aspekty związane z naprawianiem danych bezpośrednio na żywym organizmie (środowisku produkcyjnym). W zależności od komplikacji problemu poziom trudności plików SQL może być różny. Najtrudniej wykonać testy skryptów o złożonym algorytmie, który musi odpowiednio „obliczyć” dane, a następnie zmienić je sekwencyjnie w wielu tabelach. Przygotowanie środowiska w sposób pozwalający na przetestowanie skryptu naprawczego może okazać się bardzo pracochłonne lub nie­ możliwe. Ograniczenia wynikające z różnic pomiędzy środowiskiem testowym a produkcyjnym nie czynią testera zupełnie bezsilnym wobec obowiązku weryfikacji poprawki. Kon­ troler jakości może przeprowadzić analizę kodu oraz porównać aktualną i uprzednią wersję pliku itp. Dobrą praktyką jest przyjrzenie się zagadnieniu i potwierdzenie, czy obrana droga eliminacji problemu ma szanse okazać się właściwą. Ową analizę należy oprzeć na własnym doświadczeniu, znajomości systemu oraz kompetencjach technicz­ nych. Wszelkie wątpliwości należy rozstrzygnąć z autorem poprawki, gdyż czasami spojrzenie z innej perspektywy ujawni niedociągnięcia lub zainspiruje programistę. Niezależnie od możliwości zgłębienia testów zawsze należy starać się przeprowa­ dzić kontrolę przez dwie instancje (dwie ręce). Wielowątkowy rozwój systemu determinuje konieczność mnożenia pewnych elementów lub nawet całego środowiska. Związane jest to z relacjami, jakie zachodzą pomiędzy poszczególnymi obszarami systemu. Modyfikacje mogą być testowane niezależnie (są przezroczyste) lub wymagają innych modułów zależnych. Duże systemy informatyczne

Rozdział 1. ♦ Ogólna teoria testowania

27

rozwijane są równolegle na różnych płaszczyznach, co przekłada się na konieczność dostosowania zasobów do bieżących potrzeb (powielanie i izolowanie środowisk). Administracja środowiskiem testów Profesjonalny zespół testów powinien dysponować zasobami, które stanowią podbu­ dowę niezależnego środowiska testów. Wspomniana autonomia wnosi nowe możli­ wości, podnosi elastyczność i efektywność testów, a zarazem stawia wyzwania. Śro­ dowisko testów jest bardzo wymagające pod względem administracji. Jest także bardzo czułe na wszelkiego rodzaju zmiany konfiguracji ze względu na zmniejszoną hermetyczność. Systemy produkcyjne zarządzane są w oparciu o bardzo restrykcyjne wytyczne. Środowisko testów z natury musi być bardziej otwarte i podatne na zmiany w konfiguracji, modyfikacje kodu, zmiany danych etc. Zaspokojenie potrzeb zespołu testerów wymaga zwiększenia uprawnień do pewnych obszarów środowiska, wskutek czego zmniejsza się promień twardego kręgu bezpieczeństwa i równocześnie podnosi ryzyko destabilizacji pracy. Skuteczną i efektywną praktyką jest włączenie w szeregi zespołu testów osoby, która obejmie obowiązki administratora. Idealnym rozwiąza­ niem jest powierzenie zadań administracyjnych jednemu z członków grupy testerów, gdyż taka osoba doskonale rozumie potrzeby zespołu. Niemniej jednak realizacja owego scenariusza może być kłopotliwa w krótkiej perspektywie czasu ze względu na możliwe luki w kompetencjach. Generalnie administrator środowiska powinien dążyć do jak najlepszego zrozumienia istoty testów, specyfiki systemu i potrzeb z tego wy­ nikających. Środowisko testów nie jest monolitem. Nieustannie się zmienia. Z każdym nowym projektem przechodzi do stanu bardziej złożonego. Wymaga to wzmożonej czujności administratora, ale także odpowiedzialności każdego z kontrolerów jakości w ramach posiadanych uprawnień do systemu. Od administratora środowiska testów powinno oczekiwać się: ♦ zagwarantowania ciągłości pracy, ♦ stabilności środowiska, ♦ wsparcia technologicznego (w tym konsultacji), ♦ rozwijania zasobów w odpowiedzi na potrzeby. Administrator jest zobowiązany wydać opinię o możliwościach, wolnych zasobach, zagrożeniach i krokach przygotowawczych na etapie planowania testów. Pewna grupa testów może znacząco obciążyć zasoby (np. hurtowy import danych oraz ich przetwo­ rzenie), czego efektem będzie uniemożliwienie kontynuowania prac przez pozosta­ łych członków zespołu. W takich okolicznościach należy rozważyć izolację testów, tj. przenieść je w odrębne środowisko. Planując testy, należy rozważyć w aspekcie środowiska testów: ♦ konieczność separacji projektu lub jego fragmentu od podstawowego środowiska testów, np. testów wydajnościowych lub funkcjonalnych z dużą liczbą danych; ♦ możliwość uruchomienia dodatkowych serwerów aplikacji lub zupełnie nowych komponentów, np. serwera SMTP, WWW itp.;

28

Testowanie oprogramowania. Podręcznik dla początkujących

♦ ryzyko utraty lub „zepsucia” danych np. w przypadku testu jednorazowych skryptów bazodanowych (skrypt można wykonać tylko raz, w celu ponownego testu należy przywrócić pierwotny stan bazy); ♦ możliwość chwilowego włączenia do infrastruktury zasobów zdalnych, np. zewnętrznego web service, który został „użyczony” na czas testów. Wachlarz potencjalnych potrzeb jest bardzo szeroki. Administrator środowiska to osoba najbardziej kompetentna do oceny stanu i możliwości zasobów oraz ewentualnego ryzy­ ka. Niemniej jednak administrator musi być powiadomiony przez kierownika testów o potrzebach i planie wykorzystania zasobów, tak aby mógł wypracować optymalne rozwiązanie. Warto nadmienić, że administrator nie jest wyrocznią, a proponowane zało­ żenia powinny zabezpieczać interesy obu ze stron. Środowisko testów powinno być szczelnie chronione przed nieautoryzowanym dostępem szczególnie ze strony działu produkcji. Programiści mają nawyk debugowania i wy­ konywania poprawek w środowisku testowym. Niestety bardzo często pozostawiają „śmieci” w kodzie lub modyfikacje usuwające błąd. Administrator powinien ściśle re­ glamentować dostęp do środowiska testów dla osób wykraczających poza krąg kontrole­ rów jakości. Powodzenie projektu wymaga współpracy międzyzespołowej, dlatego sy­ tuacje „goszczenia” programisty w środowisku testów są nieuniknione. Niemniej jednak każda taka ingerencja powinna być autoryzowana i rozpowszechniona wśród człon­ ków zespołu testów. Samowolne działania programistów mogą spowodować koniecz­ ność powtarzania testów oraz raportowanie „fałszywych” błędów. Tester musi mieć pewność, że obserwowane działanie systemu jest wynikiem wykonania rzeczywistego kodu, takiego, do którego ma zaufanie. Kontrola jakości powinna obejmować oficjalnie wydany materiał. Wszelkie modyfikacje programisty muszą mieć charakter tymcza­ sowy i odbywać się pod kontrolą. Programista po zakończeniu prac powinien przy­ wrócić środowisko do stanu pierwotnego oraz przygotować oficjalną poprawkę, którą zweryfikuje tester. Środowisko testów powinno funkcjonować w sposób przewidywalny, stabilny i ciągły. Wśród czynności administracyjnych są takie, które można rozpocząć dopiero w mo­ mencie zwolnienia środowiska przez zespół testów — np. rozszerzenia sprzętu, kopie bazy, restarty serwera itp. Oczywiście nie zawsze można zaplanować te czynności, gdyż mogą one wystąpić w reakcji na niespodziewane incydenty. Niemniej jednak od administratora należy wymagać, aby optymalizował czynności.

1.4. Replikacja błędów Elementarną zasadą procesu eliminacji wady aplikacji jest wykonanie replikacji błędu. Replikacja polega na odtworzeniu błędu w środowisku deweloperskim i/lub testowym. Celem owego zabiegu jest potwierdzenie wystąpienia problemu, zebranie danych o okolicznościach ujawnienia się błędu oraz zaplanowanie testów. Odwzorowanie sytu­ acji, w której występuje błąd, umożliwi ułożenie adekwatnych przypadków testowych oraz wytworzy idealne środowisko do potwierdzenia skuteczności wykonanej po­ prawy kodu.

Rozdział 1. ♦ Ogólna teoria testowania

29

Replikacje błędu stosuje się w celu: ♦ weryfikacji zasadności zgłoszenia, które spłynęło ze środowiska produkcyjnego (klient zewnętrzny); ♦ przygotowania środowiska testowego, weryfikacji skuteczności poprawki; ♦ wsparcia prac programistycznych. W ramach przyjętej odpowiedzialności system powinien być serwisowany, zatem wszel­ kie zgłoszenia odnoszące się do zachowania aplikacji muszą być rozpatrywane. Nie wszystkie przypadki można zakwalifikować jako błąd, gdyż wykraczają poza obszar zdefiniowanych wymagań (rozbudowa funkcjonalności) lub też określone funkcje sys­ temu zostały użyte niezgodnie z wytycznymi (błędy procedur, pomyłki użytkowników, błędy danych etc.). Wstępna selekcja zgłoszeń ogranicza koszty związane z serwiso­ waniem systemu. Zdarza się, że czas wykonania testu stanowi niewielki ułamek całkowitego kosztu przygotowania środowiska. Systemy o wysoce skomplikowanej logice biznesowej i/lub architekturze mogą okazać się czasochłonne pod względem „dojścia” do momentu wy­ stąpienia błędu. Skuteczność poprawki możliwa jest do zbadania w momencie zrozu­ mienia istoty problemu. Testy poprawki na odpowiednio spreparowanym środowisku stwarzają szansę uzyskania miarodajnego rezultatu. Z uwagi na ograniczone kompetencje obsługi systemu poprzez interfejsy lub wąskie środowisko (niepełna architektura, mały wolumen danych, tymczasowa konfiguracja etc.) programista nie zawsze jest w stanie samodzielnie odtworzyć błąd. Tester w ra­ mach swoich kompetencji stanowi wsparcie dla zespołu programistów w materii sy­ mulacji błędu i weryfikacji poprawki. Odtworzenie błędu niesie ze sobą dodatkową wartość w postaci wyznaczenia miejsca, od którego należy rozpocząć testy. Ów punkt stanowi marker, od którego testy po­ winny być poszerzane (testy regresywne po potwierdzeniu skuteczności poprawki). Groźnym zjawiskiem jest pomijanie etapu symulacji błędu. Przystąpienie do weryfi­ kacji kodu bez uprzedniego zapoznania się z problemem może spowodować, że wy­ konany test będzie nietrafiony. Tester może wykonać przypadek testowy, który nie pokryje modyfikowanego obszaru lub nie ujmie specyficznych okoliczności wystę­ powania błędu. Próba replikacji błędu powinna być podejmowana za każdym razem. Niemniej jednak należy mieć świadomość, że nie we wszystkich przypadkach uda się taką sytuację odtworzyć. Fakt wystąpienia skutków błędnego zadziałania systemu wymusza podję­ cie kroków zaradczych, mimo że próby odtworzenia sytuacji (środowisko klienta oraz producenta) kończą się niepowodzeniem. Niemożność reprodukcji błędu nie zwalnia z konieczności modyfikacji kodu. Modyfikacja może polegać na dodaniu dodatkowe­ go logowania zdarzeń i ulepszeniu algorytmu w podejrzanym obszarze. Zabiegi pre­ wencyjne wykonywane są w oparciu o analizę kodu, doświadczenie i przeczucie pro­ gramisty. Zdarzenia o charakterze jednostkowym, incydentalne są bardzo trudne do odtworzenia, dlatego też wykonywane są modyfikacje asekuracyjne, które w przyszło­ ści pozwolą dowiedzieć się więcej o istocie problemu.

30

Testowanie oprogramowania. Podręcznik dla początkujących

1.5. U mnie błąd nie występuje Środowisko deweloperskie nigdy nie powinno być używane jako podstawowe śro­ dowisko testów! Sentencja ta powinna być powtarzana jak mantra, a treść wymawia­ nej formuły przestrzegana bezwzględnie. Separacja owych środowisk wymusza za­ chowanie czujności — podjęcie testów — już na etapie instalacji aplikacji (łącznie z instrukcją wgrania). Szczególnie irytującym zachowaniem ze strony zespołu deweloperskiego jest cofanie zgłoszonych błędów z komentarzem „u mnie to działa”. Jest to zachowanie wielce nieodpowiedzialne, wręcz patologiczne. Naznaczone jest brakiem współodpowiedzialno­ ści za projekt. Dopóki tester nie wyjaśni przyczyny wykrytego problemu, nie może w standardowych okolicznościach zgodzić się na oficjalne wydanie produktu. Wszelkie nieoczekiwane zachowania systemu odbiegające od założonego powinny być traktowane jako błąd, nawet jeżeli programista ma trudności w odtworzeniu ana­ logicznej sytuacji u siebie. Gotowe komponenty są ekstrahowane ze środowiska de­ weloperskiego, a następnie implementowane w środowisku testowym. Kod aplikacji nie może zostać uznany za poprawny, jeżeli nie przejdzie pomyślnie wszystkich przewi­ dzianych testów przynajmniej w jednym autonomicznym środowisku. Potencjalne przyczyny błędów/problemów, które nie znajdują odwzorowania w śro­ dowisku programistycznym: ♦ kod programu nie został wprowadzony do repozytorium systemu kontroli wersji, w konsekwencji nie został przekazany do działu testów; ♦ testowana aplikacja zawiera błędy, które ujawniły się w specyficznych warunkach, dotyczące np. ilości pamięci maszyny, konfiguracji serwera aplikacji etc.; ♦ środowisko testów zostało błędnie przygotowane. Nader często zdarzaj ą się błędy powstałe na skutek braku aktualizacji repozytorium. Naturalnie tego typu sytuacje zostaną wychwycone w fazie testów jakościowych, o ile odbywają się one w niezależnym środowisku. W innym przypadku diametralnie zwięk­ sza się ryzyko przekazania niepełnej (wadliwej) aplikacji klientowi. Pikanterii dodaje fakt, że emisja zostanie wykonana w przekonaniu o wysokiej jakości produktu. Wykryte błędy zostały poprawione w środowisku deweloperskim, ale kod nie został zaktuali­ zowany w repozytorium, np. nie załączono pliku konfiguracyjnego serwera, pliku CSS, zawieruszyła się jakaś biblioteka, brakuje skryptu bazodanowego itp. Finalnie oficjalna wersja produktu będzie odbiegać od zatwierdzonego stanu na koniec testów. Specyfika pracy programisty nie wymaga od niego, aby posiadał on w pełni funkcjo­ nalne środowisko, a z całą pewnością nie dysponuje on rzetelnym wolumenem da­ nych. Posługując się kolokwializmem, można rzec „dużo nie trzeba”, aby program zadziałał w sposób nieoczekiwany. Nie muszą to być szczególnie specyficzne sytuacje. Czasami wystarczy uruchomić system w „innym” środowisku.

Rozdział 1. ♦ Ogólna teoria testowania

31

Błędy wynikłe wskutek nieprawidłowości środowiska testów mogą być konsekwencją wadliwie sporządzonej instrukcji wdrożenia — notabene ona także podlega kontroli — lub niedokładnie przeprowadzonej konfiguracji. W przypadku kiedy instrukcja in­ stalacji nie zaspokaja potrzeb, należy ją poprawić lub uzupełnić. Powyższe przesłanki umacniają pogląd, że testy powinny być wykonywane w nieza­ leżnym środowisku. Weryfikacja jakości oprogramowania w środowisku deweloper­ skim wprowadza znaczne ryzyko przeoczenia problemów, które z dużym prawdopo­ dobieństwem ujawnią się w momencie wdrażania aplikacji lub w pierwszym etapie testów u klienta. W celu zminimalizowania powyższego zagrożenia konieczne jest „przejście” oprogramowania przez środowisko inne niż deweloperskie. Równie istotne co same testy jakościowe są warunki, w których pracuje aplikacja. Kod można uznać za poprawny, jeżeli spełnia wymagania biznesowe oraz jest uruchamialny w różnych środowiskach, które spełniają zdefiniowane wymagania. Więcej informacjo o aspektach przenośności kodu oraz testów instalacji zostanie przy­ toczonych na dalszych kartach niniejszej publikacji.

1.6. Symulatory aplikacji oraz generatory danych Informacja jako dobro niematerialne odgrywa coraz bardziej istotną rolę w życiu społeczno-ekonomicznym. Rosnące przystosowanie i gotowość do posługiwania się nowymi technologiami informatycznymi stymulują rozwój usług związanych z prze­ syłaniem, przetwarzaniem i gromadzeniem danych. Społeczeństwo informacyjne bły­ skawicznie asymiluje nowe technologie w codziennym życiu politycznym, społecz­ nym i gospodarczym. W celu zaspokojenia owego apetytu tworzone są coraz bardziej wyrafinowane i skomplikowane systemy informatyczne. Pojedyncza operacja, jedna czynność inicjowana przez jednostkę społeczeństwa angażuje wiele różnych syste­ mów informatycznych. Osoba zgłaszająca chęć skorzystania z określonej usługi aż do momentu otrzymania ostatecznego wyniku nie jest szczegółowo angażowana w ko­ lejne kroki wykonania operacji. Proces, przechodząc przez wiele różnych instytucji, przetwarzany jest w oparciu o heterogeniczne obiekty informatyczne. Ochrona myśli technicznej stanowi podstawowy, a zarazem najważniejszy obowiązek każdej korpo­ racji. Oprogramowanie — w ujęciu całościowym systemu — pisane na zlecenie jed­ nego zamawiającego, ale produkowane przez kilka autonomicznych przedsiębiorstw, musi w pewnym momencie zostać zintegrowane. Intencją klienta jest uzyskanie okre­ ślonego efektu końcowego (biznesu), który będzie realizowany przy współpracy wielu programów. Przy założeniu, że aplikacja zlecona korporacji A musi komuni­ kować się z programem B i oba z tych modułów jeszcze nie istnieją, automatycznie pojawia się pytanie o możliwość wykonania pełnych testów. Dodatkowym utrudnie­ niem może okazać się brak woli podjęcia dostatecznej współpracy z firmą bądź co bądź konkurencyjną, która produkuje odrębny element. Formułując wymagania, klient powinien przedłożyć specyfikację metody komunikacji pomiędzy programami. Metoda wymiany danych w postaci plików jest mniej problematyczna, o ile jesteśmy w po-

32

Testowanie oprogramowania. Podręcznik dla początkujących

siadaniu szczegółowej dokumentacji. Spreparowanie plików niezbędnych do importu może okazać się trudne, pracochłonne i nużące, ale nie musi wymagać umiejętności stricte programistycznych. Znacznie trudniej wykonać testy obszarów, które wyma­ gają komunikacji z innym systemem w czasie rzeczywistym, np. web service. Testy opcji wysyłającej żądanie do web service oraz modułów zależnych nie będą możliwe bez zaślepienia wtyczki. Zmaterializowanie się owej potrzeby wymusza stworzenie do­ datkowego narzędzia, jakim jest symulator. Symulator to autonomiczny program, który imituje działanie właściwego programu lub urządzenia. Zwykle logika biznesowa takiego programu jest mocno ograniczona, choć powinien on zabezpieczyć w pełni aspekt techniczny, np. odbierać i wysyłać żąda­ nia web service zgodnie ze specyfikacją pliku WSDL. Symulator automatycznie staje się częścią środowiska testowego. Powinien on być modyfikowany i serwisowany równo­ legle z implementacją zmian w aplikacji, którą wspiera. Fakt istnienia zaślepek zmniejsza obszary martwe, w których testy ze względu na luki w środowisku nie mogłyby być wykonane. Zagęszczenie sita kontroli wpłynie dodat­ nio na końcową jakość produktu. Kompetencje symulatora mogą odnosić się do wielu różnych dziedzin. Może on pod­ szywać się pod jakieś urządzenie, pojedynczy czujnik, web service etc. Zadaniem te­ stera jest wykrycie na etapie planowania testów konieczności przygotowania zaślepki. Ujawnienie zapotrzebowania na takie rozwiązanie powinno być oficjalnie sformuło­ wane i przekazane do osoby kompetentnej. Fakt identyfikacji problemu nie rozwią­ zuje go. Zespół kontroli jakości może mieć duże problemy z uzyskaniem zaślepki od działu programistycznego ze względu na napięty harmonogram lub dodatkowe koszty. Mogą się też pojawić trudności w wypracowaniu wspólnego stanowiska co do funk­ cjonalności samego symulatora. Z punktu widzenia testów zakres działania symulato­ ra może okazać się niesatysfakcjonujący, choć dla działań programistycznych będzie on optymalny. Rozwijanie podstawowych kompetencji programistycznych wydaje się właściwym to­ rem prowadzącym do uzyskania niezależności i poprawy skuteczności testów. Stwo­ rzenie zaślepki własnymi siłami (zespół testów) zagwarantuje elastyczność w trakcie serwisowania systemu. Niewątpliwie ten stan rzeczy nie ujdzie uwadze w zespole deweloperskim i rzuci cieplejsze światło na kompetencje testera, który do tego momentu mógł być postrzegany jako kompletny laik w obszarze programowania. Generatory danych Systemy informatyczne gromadzą i przetwarzają dane, które pochodzą z rzeczywiste­ go środowiska funkcjonowania aplikacji. Dane magazynowane są w bazach danych. Cyfrowe zbiory danych są bazowym komponentem systemów informatycznych. Ele­ mentarną zasadą jest gromadzenie rzeczywistych, spójnych i poprawnych danych. Pojedyncza baza danych może być zasobem, który jest współdzielony przez wiele autonomicznych interfejsów (aplikacji). Nierzadko skomplikowane procesy bizneso­ we angażują wiele różnych podsystemów, które z kolei mogą sięgać po dane rezydu­ jące w szeregu innych baz danych. Skomplikowana logika poparta znacznym rozpro­ szeniem danych jest bardzo podatna na błędy związane z wadami danych. W życiu

Rozdział 1. ♦ Ogólna teoria testowania

33

społecznym funkcjonuje wiele różnorodnych ciągów znaków, które służą za identyfi­ katory osób, rzeczy lub stanowią referencję do pewnych sytuacji lub obiektów wirtu­ alnych. Zwykle każdy z owych identyfikatorów posiada ściśle zdefiniowaną strukturę, która oprócz założonych cech, jak np. unikalność, może nieść ze sobą konkretne in­ formacje, np. płeć w numerze PESEL. Oficjalny standard danych pozwala na prze­ twarzanie zbiorów danych przez różne systemy, które uprzednio były przygotowane do ich obsługi według specyfikacji. W celu utrzymania standardu danych implementuje się mechanizmy walidacyjne. Mogą one być zaszyte w interfejsach użytkownika (GUI) lub w algorytmach importu danych z plików zewnętrznych. W systemach heterogenicznych powszechnie stosuje się język XML, na przykład tworząc opis usługi sieciowej WSDL (ang. Web Services Description Language).

Algorytmy walidacyjne danych wejściowych mogą być skomplikowane. Ręczne przygotowanie rzeczywistych danych, np. numeru PESEL, REGON czy NIP, może okazać się kłopotliwe. Rzeczą naturalną wydaje się konieczność posłużenia się sto­ sownym generatorem, który przygotuje poprawne dane. Wartością programów wy­ twarzających dane jest ich szybkość działania oraz możliwość produkcji hurtowej ilości wsadu na przykład do pliku importu. Internet obfituje w darmowe narzędzia generu­ jące powszechne dane, tj. PESEL, REGON, NIP, nr dowodu osobistego, IBAN oraz wiele innych typów. Zdarzają się sytuacje, kiedy przypadek testowy wymaga użycia danych o ściśle zdefiniowanym standardzie, lecz niebędących w powszechnym (pu­ blicznym) użyciu. Uprzednio wywołana konieczność rozwijania elementarnych umiejęt­ ności programistycznych w tym miejscu ponownie znajduje uzasadnienie. Rzeczywiste dane zbliżają testy do naturalnej obsługi systemu, w konsekwencji czego możliwa jest obserwacja zachowania aplikacji w okolicznościach, do jakich została zaprojektowana. Realne dane wzmacniają skuteczność testów logiki oraz warstwy pre­ zentacji systemu. Posługiwanie się naturalnie występującymi danymi zwiększa efek­ tywność testowania raportów i interfejsów graficznych na przykład w okolicznościach: ♦ podawania więcej niż jednego imienia i/lub dwuczłonowego nazwiska, np. Maria Salomea Skłodowska-Curie (ur. 7 listopada 1867, zm. 4 lipca 1934); ♦ podawania łączonych nazw miejscowości, np. Janów Lubelski; ♦ podawania nazw własnych, które używają znaków specjalnych, np. Fundacja „Jaś i Małgosia”; ♦ podawania adresów korespondencyjnych używanych w Polsce i na świecie; ♦ podawania telefonów w sieciach krajowych lub zagranicznych. Środowisko testowe służy również jako zaplecze do prac dokumentalistów, na przy­ kład podczas tworzenia instrukcji użytkownika. Zwykle owe dokumenty zawierają zrzuty ekranów z GUI. Rzeczywiste dane testowe uwiarygodniają jakość systemu oraz wzbudzają zaufanie do zawartości merytorycznej dokumentu. Tester ma prawo oraz obowiązek nieco zgrzeszyć. Kontrola jakości nie może opierać się jedynie na idealnie poprawnych zestawach danych. Interfejsy użytkownika powinny być sprawdzone pod kątem wprowadzania przypadkowych i nienaturalnych danych

34

Testowanie oprogramowania. Podręcznik dla początkujących

z dużym naciskiem na znaki, które są w sposób szczególny traktowane przez języki programowania, np. %, &, ! itp. Niemniej jednak baza danych nie powinna być uzu­ pełniana jedynie losowymi i abstrakcyjnymi danymi.

1.7. Dokumentowanie testów Dokumentowanie wykonania testów jest zagadnieniem budzącym kontrowersje oraz mieszane uczucia. Testerowi trudno dostrzec wartości płynące z tego działania, gdyż często odbiera on ten wymóg jako formę sprawowania kontroli nad jego pracą i sprawdzania, czy i w jaki sposób wykonuje powierzone zadania. Nienegowanym fak­ tem jest, że powstała dokumentacja może posłużyć do tego celu. Niemniej jednak nie jest to jej kluczowe zadanie i nie powinno być ono priorytetem w trakcie oceny i analizy materiału. Przebieg testów dokumentuje się w celu: ♦ ewentualnego przedłożenia klientowi raportu z zakresu, metody i powodzenia testów; ♦ potwierdzenia wykonania testów w założonym zakresie; ♦ zebrania szczególnie trudnych i istotnych warunków wejściowych w celu zabezpieczenia możliwości ponownego odtworzenia sytuacji w przyszłości; ♦ stworzenia repozytorium wskazówek, które mogą pomóc innym w wykonaniu analogicznego testu; ♦ wyłączenia odpowiedzialności lub odparcia zarzutów w sytuacjach spornych. Dokumentacja wykonania testów odgrywa szczególną rolę w podnoszeniu efektyw­ ności procesu testowania, a tym samym jakości finalnego produktu. W oparciu o ów materiał można przeprowadzić rewizję pokrycia aplikacji testami oraz ich skuteczno­ ści. Zgromadzony materiał „dowodowy” powinien wskazać ewentualne luki w scena­ riuszach lub wręcz potwierdzić trafność zaprojektowanych testów. Taką ocenę można wykonać poprzez merytoryczne porównanie błędów zgłoszonych w fazie odbioru opro­ gramowania (klient) z przypadkami wykonanymi w firmie. Wysunięte wnioski po­ winny wyznaczyć kierunek do korekty i udoskonalenia testów. Dokumentacja wykonania testów powinna zawierać: ♦ informacje o środowisku, takie jak nazwa bazy danych, wersje aplikacji, identyfikator scenariusza/przypadku, którego dotyczy; ♦ zrzuty ekranu z momentu wykonywania i przygotowywania testu; ♦ wyciągi danych z bazy; ♦ opis istotnych warunków, parametrów wejściowych itp. Proces dokumentowania testów nie może przesłonić idei wykonywania testów. Zbieranie materiału powinno odbywać się w tle i nie determinować kreowania testu pod kątem zrobienia dobrego zrzutu. Za patologię należy uznać dokumentowanie wszystkich

Rozdział 1. ♦ Ogólna teoria testowania

35

czynności, które odbywają się poprzez analogię do siebie, np. wielokrotne zrzuty tego samego obszaru w bardzo zbliżonych okolicznościach obsługi. Sporządzony materiał tester powinien traktować jako wartość, która z założenia ma wpłynąć pozytywnie na jego kompetencje i efektywność pracy.

1.8. Kontrola wersji oprogramowania Efektywny proces produkcji oprogramowania obligatoryjnie powinien być wspierany przez system kontroli wersji (ang. version control system). Owo oprogramowanie słu­ ży do śledzenia zmian w kodzie źródłowym, pomaga również w zachowaniu spójno­ ści repozytorium. Nowoczesna specyfika i kultura pracy korporacji charakteryzują się decentralizacją zasobów ludzkich. Oznacza to, że nad wspólnym przedsięwzięciem mogą pracować osoby rezydujące w różnych lokalizacjach geograficznych. Powyższe okoliczności ujawniają pierwszą konieczność zastosowania systemu, który pozwoli na łączenie i przechowywanie zmian dokonanych przez różnych programistów (współ­ dzielenie zasobów — plików). Kolejnym zadaniem wspomnianego oprogramowania jest gromadzenie historii zdarzeń poczynionych na kodzie źródłowym. Metryka mo­ dyfikacji źródła wykorzystywana jest do analizy okoliczności zmian w kodzie. Na tej podstawie możliwe jest odtworzenie sekwencji zdarzeń, wskutek których wprowa­ dzona została badana implementacja. Namierzenie momentu, w którym naniesione zostały krytyczne (negatywne) lub istotne (ważne) zmiany w produkowanej aplikacji, pozwoli na dotarcie do genezy zagadnienia. Repozytorium to element, który skupia wszystkich zainteresowanych w obrębie jed­ nego projektu. Fakt ten wymusza zachowanie najwyższej ostrożności i odpowiedzial­ ności za bazę danych, tak aby cieszyła się ona maksymalnie dużym zaufaniem, a jej za­ soby nie budziły żadnych wątpliwości (dobro wspólne). Dużym zagrożeniem dla tego celu jest skłonność programistów do opieszałej publikacji materiału lub wręcz do­ grywanie plików po fakcie zbudowania emisji (kompilacji) ze wskazanego źródła. Popularnym systemem kontroli wersji jest Subversion (SVN). Cechą charakterystycz­ ną oprogramowania SVN jest dokonywanie transakcji atomowych. Oznacza to, że operacja przyniesie skutek, tylko jeżeli wszystkie pliki w sposób poprawny zostaną sko­ piowane. Takie rozwiązanie zabezpiecza przed sytuacją częściowej modyfikacji danych. Strona domowa projektu: http://subversion.apache.org/. Kolejnym ciekawym i równie popularnym rozproszonym systemem kontroli wersji jest GIT. Oprogramowanie zostało wydane w oparciu o licencję GNU GPL. Strona domowa projektu: http://git-scm.com/. System kontroli wersji nie rozwiązuje wszystkich problemów związanych z produkcją i emisją oprogramowania. Pożądanym uzupełnieniem lub wręcz podbudową do wdro­ żenia aplikacji typu SVN jest stosowanie tak zwanych dobrych praktyk korporacyj­ nych. Normatywy regulują nazewnictwo plików, zasady podnoszenia numeru wersji, opisy źródła modyfikacji etc. Tworzą podstawowe ramy współpracy. Żelazne pod­ stawy kooperacji gwarantują niezbędne minimum w komunikacji pomiędzy działami i osobami uczestniczącymi w projekcie.

36

Testowanie oprogramowania. Podręcznik dla początkujących

Do dobrej praktyki powinno należeć: ♦ wersjonowanie obiektów, ♦ spójne nazewnictwo i oznaczanie plików, ♦ opisywanie zmian (metryka), ♦ opisywanie kodu. Złożone systemy informatyczne składają się z wielu modułów, których współdziałanie coraz częściej wykracza poza relację jeden do jednego. Architektura wielowarstwowa (ang. multi-tier architecture) rozdziela interfejs użytkownika oraz obszar składowania i przetwarzania danych na osobne warstwy. Wielomodułowość komplikuje proces zarzą­ dzania wersjami poszczególnych elementów. Standardem jest numerowanie i „podbi­ janie” wersji dla całych aplikacji powstałych w wyniku kompilacji kodu (EXE, WAR, EAR). Niestety często zaniedbywane pod tym względem są luźne obiekty wchodzące w skład całego systemu, tj. pliki JavaScript (JS), CSS, HTML, biblioteki etc. W przy­ padku ujawnienia się wątpliwości odnośnie do zawartości merytorycznej tylko autor kodu poprzez jego analizę będzie w stanie ustalić, czy przekazany plik jest właściwy. Luki w wersjonowaniu obiektów wygenerują koszty w postaci dodatkowych zapytań do programisty, zwielokrotnienia obsługi administracyjnej tego samego materiału. Następstwem ograniczonego zaufania do elementów, które nie posiadają wersji, bę­ dzie wzmożenie czynności mających na celu weryfikację aktualności otrzymanych plików. Dojrzałym sposobem praktycznej realizacji wersjonowania jest pisanie dedy­ kowanych funkcji, które zwracają identyfikator obiektu. W sytuacji kiedy zastosowana technologia utrudnia takie rozwiązanie, należy oznaczyć plik poprzez komentarz w ko­ dzie. Listing nr 1.4 prezentuje funkcję zwracającą wersję pakietu w bazie Oracle. Wynik działania tej funkcji prezentuje rysunek 1.8. Listing 1.4. Pakiet w bazie Oracle z zaimplementowaną funkcją zwracającą jego wersję____________ c r e a t e o r r e p l a c e package t b o o k _ p a k i e t i s -- A uthor : R AF AL P AW LAK -- C reated : 2013-10-27 22:09:12 -- Purpose : P akiet służy do realizacji dyspozycji doładowania telefonu. Księguje. -- Zmienna: przypisuje wersję pakietu w e r s j a Va r char 2( 10) : = ' 1 . 0 . 0 ' ;

-- D eklaracja funkcji f u n c t i o n d a j _ w e r s j e r e t u r n Var char 2; end t b o o k _ p a k i e t ; / c r e a t e o r r e p l a c e package body t b o o k _ p a k i e t i s -- F unkcja zw racająca wersję pakietu tbook_pakiet f u n c t i o n d a j _ w e r s j e r e t u r n Var char 2 i s

Rozdział 1. ♦ Ogólna teoria testowania

37

beg r etu rn wersja; end; end t b o o k _ p a k i e t ; I

Rysunek 1.8. Wywołanie funkcji zwracającej wersję pakietu Oracle

S Q L > sec s e r v e r ou c p u c on; 5 QL> S Q L > d e clare 2

j a k a _ w e r s j a V a r c h a r 2 (10) ;

3

begin

4

jaka_wersja

5

:= CbooJc_paJciet.d a j _ w e r s je;

dbrr.s_output .put_line ('Wersja p a k i e t u to: 1 || j a k a _ w e r s j a ) ;

6

end;

7

/

W e r s j a p a k i e t u to:

1.0.0

PL/ S Q L p r o c e d u r e s u c c e s s f u l l y c o m p l e t e d S QL>

Szczególnie uciążliwy jest brak wersjonowania obiektów bazodanowych. W takich oko­ licznościach serwisowanie tego modułu jest bardzo trudne i kosztowne. Ustalenie, w jakim kodzie („wersji”) został wykryty problem, wymaga odwołania się bezpośrednio do środowiska (kodu w bazie). Niewątpliwie przełoży się to na trudności w replikacji błędu w środowisku testowym, a co za tym idzie, wykonana poprawka może okazać się nieskuteczna. Pożądaną praktyką jest zagnieżdżanie w plikach metryki, która poświadczy pocho­ dzenie i cechy obiektu. Ów zabieg najczęściej stosuje się do materiałów przygotowa­ nych w języku znaczników lub językach skryptowych, o ile nie wpłynie to negatyw­ nie na bezpieczeństwo systemu (czytanie kodu źródłowego przez osoby postronne). Wspomniana metryka powinna zawierać informacje o autorze kodu, dacie i przyczy­ nie ostatniej modyfikacji, historię zmian, zależności od innych obiektów, wersję itp. Przykład metryki dla pliku SQL przedstawia listing nr 1.5. Listing 1.5. Metryka pakietu Oracle c r e a t e o r r e p l a c e package t b o o k _ p a k i e t i s -- A uthor : R AF AL P AW LAK -- C reated : 2013-10-27 22:09:12 -- P urpose : P akiet służy do realizacji dyspozycji doładowania telefonu. Księguje. /* M etryka zm ian 1.2.1 - Popraw a literówki w kom unikacie błędu by R .P aw lak 2013-10-27 1.2.0 - D odanie nowej funkcji sprawdz_status_realizacji by R.K ow alski 2013-09-21 1.1.0 - D odanie nowej funkcji anuluj_dyspozycje by R.K ow alski 2013-09-01 1.0.2 - Zwiększenie zakresu zm iennej A B C 1.0.1 - Popraw a obsługi wyjątków 1.0.0 - Pow ołanie pakietu na potrzeby funkcjonalności: doładowania telefonów */

38

Testowanie oprogramowania. Podręcznik dla początkujących

-- Zmienna: przypisuje wersję pakietu w e r s j a Va r char 2( 10) : = ' 1 . 2 . 1 ' ; —D eklaracja funkcji f u n c t i o n d a j _ w e r s j e r e t u r n Var char 2; end t b o o k _ p a k i e t ;

Zwyczaj opisywania kodu źródłowego (ang. source code) w trakcie prac programi­ stycznych może okazać się zbawienny w momencie konieczności szybkiej analizy problemu, niedostępności programisty lub zakończenia współpracy z autorem. Ko­ mentowanie kodu stanowi również ułatwienie dla testera, który nierzadko musi po­ chylić się nad instrukcjami języka programowania. Przykład opisywania kodu źródłowego przedstawia listing 1.6. Listing 1.6. Przykład opisywania kodu źródłowego c r e a t e o r r e p l a c e package body t b o o k _ p a k i e t i s —F unkcja zw racająca wersję pakietu tbook_pakiet f u n c t i o n d a j _ w e r s j e r e t u r n Var char 2 i s begi n re t ur n wersja; end; —F unkcja weryfikuje kwotę doładowania, tj. odrzuca zlecenie, jeżeli kw ota > 1000 zł f u n c t i o n s pr awdz_kwot e(kwot a i n Number) r e t u r n Var char 2 i s begi n —B lo k warunkowy, weryfikacja kw oty i f kwota > 1000 then kwota_odp := ' z a d u ż o ' ; else kwota_odp := ' o k ' ; end i f ; r e t u r n kwota_odp; end; end t b o o k _ p a k i e t ; /

Podnoszenie wersji obiektu nie powinno stanowić jedynego ułatwienia w zarządzaniu repozytorium. Tam, gdzie to możliwe, trzeba dodatkowo wprowadzić system admini­ stracji nazwami plików. Obszarem, który idealnie się do tego nadaje, jest zbiór skryptów bazodanowych. Z uwagi na to, że skrypty są wykonywane na bazie i na skutek takiej akcji dopiero są powoływane (modyfikowane) obiekty lub dane, powinno się takie pliki SQL odpowiednio (unikatowo) oznaczać. Algorytm nadawania niepowtarzalnych nazw plikom skryptowym pozwoli na przechowywanie wszystkich plików w jednym miejscu, zabezpieczy możliwość powrotu do poprzedniej wersji obiektu, np. pakietu, ułatwi stworzenie całościowej instrukcji wgrania. Podmienianie plików jest bardzo niepokojącym zjawiskiem, które stwarza zagrożenie utraty kontroli nad przebiegiem

Rozdział 1. ♦ Ogólna teoria testowania

39

procesu wytwórczego. Rysunek nr 1.9 prezentuje przykład nagannej obsługi pliku SQL, który implementuje zmiany w pakiecie w bazie danych. Rysunek nr 1.10 obra­ zuje prawidłowy algorytm postępowania. Rysunek 1.9. Naganna obsługa przekazywania zmian w kodzie

Rysunek 1.10. Prawidłowa obsługa przekazywania zmian w kodzie

M o d y fik a c ja

Mechanizm oznaczania (nazywania) plików zawsze powinien być dopasowany do kultu­ ry pracy i wymogów przedsiębiorstwa bez względu na to, czy odnosi się to do obiektów o trwałej nazwie, czy skryptów wykonywanych na bazie. Celem wprowadzenia takie­ go standardu jest zachowanie spójności, przejrzystości i optymalizacja kosztów obsługi administracyjnej repozytorium. Obowiązkiem członków zespołu jest przestrzeganie wypracowanych zasad.

1.9. Obsługa zgłoszeń Efektywne zarządzanie i obsługa zgłoszeń dotyczących funkcjonowania sytemu sta­ nowią podstawę w podnoszeniu jakości oprogramowania. Ów warunek dotyczy rów­ norzędnie zarówno zgłoszeń wewnętrznych, jak i zewnętrznych. Najczęściej do ra­ portowania i dalszej administracji błędami wykorzystuje się dedykowane w tym celu oprogramowanie, takie jak: ♦ Bugzilla wyprodukowane przez Fundację Mozilla (ang. The Mozilla Foundation) na licencji Mozilla Public License (MPL), strona domowa projektu: http://www. bugzilla. org/.

♦ M antis Bug T racker na licencji GNU General Public License (GNU GPL), strona projektu: http://www.mantisbt.org/. ♦ JIR A firmy Atlassian na licencji komercyjnej. Źródło, z którego napływa zgłoszenie, determinuje pewne modyfikacje podstawowego algorytmu obsługi błędów. Błędy zewnętrzne, tj. takie, które zostały wykryte i udo­ kumentowane poza środowiskiem testów producenta, wymagają zwiększonej liczby

40

Testowanie oprogramowania. Podręcznik dla początkujących

kroków w procesie obsługi niż błędy wewnętrzne. Niemniej jednak większość reguł postępowania dla obu typów zgłoszeń ma charakter wspólny. Oba typy błędów po­ winny być obsługiwane w tym samym systemie z zastrzeżeniem niejawności zgłoszeń wewnętrznych dla osób postronnych (klientów). Błędy zewnętrzne pochodzą również ze środowiska produkcyjnego, dlatego też klienci są żywo zainteresowani śledze­ niem bieżących postępów prac. Budowanie trwałych i stabilnych relacji z potencjal­ nymi klientami wymaga dużej elastyczności w postępowaniu, choć nie ma najmniejszej potrzeby dzielić się problemami, które zostały wykryte po stronie producenta. Rysunek 1.11 przedstawia podstawowy algorytm obsługi błędów zgłoszonych przez klienta.

Klient W ykrycie błędu, przekazanie do producenta (0)

Realizacja, przekazanie do testów (4)

Analiza, odrzucenie lub realizacja przez program istę (3)

W stępne przyjęcie w serw isie (1)

Rejestracja w system ie, przyjęcie lub odrzucenie (2)

Punkt DECYZYJNY

Punkt DECYZYJNY

T esty jakościow e, akceptacja lub cofnięcie do produkcji (5)

Punkt DECYZYJNY

Emisja, koniec procesu (7)

Rysunek 1.11. Podstawowy proces obsługi błędów zewnętrznych Ciąg czynności związanych z obsługą błędu zewnętrznego składa się z następujących kroków: 0. Wykrycie błędu, skierowanie problemu do producenta. 1. Wstępne przyjęcie zgłoszenia. 2. Wprowadzenie do systemu, skierowanie do produkcji lub odrzucenie. 3. Analiza przez programistę, podjęcie zgłoszenia lub jego odrzucenie. 4. Realizacja, przekazanie do testów. 5. Testy jakościowe, akceptacja lub cofnięcie do produkcji. 6. Emisja. 7. Koniec procesu.

Rozdział 1. ♦ Ogólna teoria testowania

41

K rok 0. Na podstawie uwag płynących bezpośrednio od użytkowników systemu lub spostrzeżeń własnych zespołu testów klienta popartych dokumentacją i doświadcze­ niem formułowane jest zgłoszenie. Zgromadzony materiał przekazywany jest do pro­ ducenta oprogramowania. K rok 1. Przesłany materiał jest formalnie przyjmowany, a następnie wstępnie anali­ zowany pod kątem treści i załączników. Wkład do zgłoszenia powinien dokładnie opisywać i dokumentować problematyczną sytuację oraz zawierać wszelkie powiąza­ ne logi (w tym komunikaty błędów etc.). K rok 2. Zgłoszenie jest wprowadzane do systemu. Po wstępnym potwierdzeniu wy­ stępowania błędu w oparciu o przesłaną dokumentację zgłoszenie jest kierowane do produkcji. Odrzucenie następuje gdy: ♦ zachowanie systemu jest zgodne z wymaganiami (dokumentacją zamówienia); ♦ istota problemu wykracza poza zakres zamówienia (nie jest to błąd, lecz próba modyfikacji systemu); ♦ brakuje załączników (logów, zrzutów itp.) lub treść jest niejasna (nie można zrozumieć problemu). K rok 3. Programista szczegółowo analizuje problem, identyfikuje jego przyczynę, a na­ stępnie podejmuje decyzję o odrzuceniu lub realizacji zgłoszenia. Powodami odrzucenia mogą być: ♦ błędy danych — np. będące skutkiem sztucznej ingerencji w bazie danych lub działania innej aplikacji — które spowodowały niepożądane działanie systemu (sytuacja wykracza poza zamówiony poziom walidacji); ♦ błąd operatora/użytkownika, który złamał procedury obsługi określonej sytuacji; ♦ system zachował się poprawnie; ♦ nie udało się odtworzyć błędu i zidentyfikować przyczyny (również w środowisku produkcyjnym); ♦ błąd wystąpił na skutek problemów ze środowiskiem, za które producent oprogramowania nie bierze odpowiedzialności, lub klient nie zachował minimalnych wymogów. K rok 4. Wynikiem realizacji zgłoszenia jest przygotowanie poprawki i skierowanie jej do kontroli jakości. K rok 5. Poprawka weryfikowana jest pod kątem skuteczności. Tester akceptuje mo­ dyfikację lub kieruje problem do ponownego rozpatrzenia (błąd w dalszym ciągu wy­ stępuje). K rok 6. Modyfikacja zostaje zatwierdzona i przygotowana do emisji. Emisja nastę­ puje w sposób określony w umowie. Oprogramowanie pudełkowe zwykle jest napra­ wiane poprzez wydanie oficjalnej aktualizacji. K rok 7. Obsługa zgłoszenia zostaje zakończona.

42

Testowanie oprogramowania. Podręcznik dla początkujących

W powyższym algorytmie pominięto fazę testów wewnętrznych podejmowanych przed przekazaniem zmian do etapu testów jakościowych. Chcąc rozszerzyć tę se­ kwencję, należy wstawić dodatkowy krok testów wewnętrznych przed etap testów ja ­ kościowych. Decyzyjność dla obu etapów jest identyczna, tj. zwrot do produkcji lub akceptacja i przekazanie produktu do kolejnego kroku. W przypadku błędów wewnętrznych sekwencja zdarzeń jest nieco krótsza i mniej skomplikowana: 1. Wykrycie, udokumentowanie i zarejestrowanie błędu w systemie. 2. Analiza problemu przez programistę, odrzucenie lub skierowanie do produkcji. 3. Realizacja i skierowanie do weryfikacji. 4. Testy, przywrócenie do produkcji lub akceptacja. 5. Zatwierdzenie modyfikacji i zamknięcie zgłoszenia. Rysunek 1.12 pokazuje algorytm postępowania z błędami własnymi (wykrytymi u producenta). Błędy wewnętrzne najczęściej pojawiają się w momencie podjęcia nowego projektu testowego, tzn. modyfikacji funkcjonalności systemu lub opraco­ wywania zupełnie nowej aplikacji. Oczywiście zdarzają się sytuacje wykrycia błędów przy okazji przeglądu aplikacji lub wykonywania innych testów, ale to są z reguły sytuacje sporadyczne. Zatwierdzona poprawka oczekuje na emisję. Zwykle dzieje się to w ramach emisji nowej wersji programu lub przekazania w całości zamówionego modułu. Błędy wewnętrzne nie wymagają dodatkowej weryfikacji formalnej i mery­ torycznej. Naturalnie żaden tester nie posiada nieomylności w portfelu własnych kompetencji, niemniej jednak większość zarejestrowanych problemów powinna być poprawiona. Chcę przez to powiedzieć, że zdarza się, iż tester zgłosi niezasadny błąd, który zostanie odrzucony przez programistę. Niemniej jednak takie przypadki zwykle stanowią niewielki odsetek. Wykonanie ponownego testu (retest) nie stanowi proble­ mu z uwagi na brak konieczności zagłębiania się w istotę problemu, tak jak ma to miejsce przy obsłudze błędów zewnętrznych.

T esty jakościow e, akceptacja lub cofnięcie do produkcji (4)

Punkt DECYZYJNY

Rysunek 1.12. Podstawowy proces obsługi błędów wewnętrznych

Rozdział 1. ♦ Ogólna teoria testowania

43

Zarejestrowany błąd wędruje pomiędzy poszczególnymi etapami, zmienia również opiekuna. Dzieje się to niezależnie od etapu, na którym się znajduje. Zmiana osoby od­ powiedzialnej determinowana jest potrzebą skierowania problemu do osoby bardziej kompetentnej, np. w celu przeprowadzenia analizy, modyfikacji kodu lub wykonania testów. W ramach jednej fazy błąd może kilkakrotnie wędrować pomiędzy członkami zespołu, zanim zostanie ostatecznie obsłużony. Treść i zawartość wprowadzonego do systemu zgłoszenia powinny pozwolić na zro­ zumienie i identyfikację problemu. Niestety często wartość merytoryczna oraz jakość załączników nie odpowiada temu założeniu. Niewystarczający lub niejednoznaczny ma­ teriał wymusza podjęcie dodatkowych czynności polegających na wyjaśnianiu i usta­ laniu stanu faktycznego. Dodatkowa praca zwykle generuje koszty, które obciążają bu­ dżet producenta. Płynąca konkluzja uwiarygodnia konieczność dbania o wysoką jakość wprowadzanych zgłoszeń. Prawidłowo zarejestrowane zgłoszenie powinno minimalnie zawierać: ♦ sygnaturę scenariusza i/lub numer przypadku testowego, w trakcie którego wykonywania został ujawniony błąd (przypadek nie zakończył się poprawnie); ♦ informacje o środowisku testowym: namiar na bazę danych, serwer aplikacji itp.; ♦ zestaw danych wejściowych niezbędnych do odtworzenia (podglądu) sytuacji; ♦ zrzuty ekranu z opisem problemu; ♦ treść komunikatów błędów (o ile one wystąpiły np. w momencie przechwycenia wyjątku); ♦ pliki logów dokumentujące problematyczne zdarzenie; ♦ wersję systemu, pakietów bazodanowych, bibliotek itp., na których wykonywane były testy; ♦ klasę błędu powiązaną z priorytetem realizacji — błędy krytyczne muszą być poprawiane natychmiast, natomiast usterki mogą zaczekać (warunki obsługi definiuje umowa z klientem lub procedury wewnętrzne producenta); ♦ opcjonalnie referencję do innych obszarów, na których działanie raportowany błąd ma istotny wpływ.

1.10. Testowanie obsługi wyjątków w kodzie Obsługa i logowanie wyjątków to terminy, które nie powinny być zarezerwowane je ­ dynie dla programisty. Obsługa zdarzeń wyjątkowych w językach programowania jest realizowana na poziomie semantyki i składni owego języka. Wraz ze wzrostem kodu rośnie prawdopodobieństwo pojawienia się wyjątku (ang. exception). Programiści do­ kładają wszelkich starań, aby obsłużyć jak najwięcej sytuacji mogących wygenerować błędy, choć eliminacja wszystkich zagrożeń jest niemożliwa. Błędy występują w każdej

44

Testowanie oprogramowania. Podręcznik dla początkujących

aplikacji. Uszczelnianie programu przed niepożądanymi sytuacjami diametralnie zwiększa ilość kodu, który zamazuje właściwą logikę. Oczywiście duży zbiór pro­ blemów musi zostać obsłużony przy świadomej ingerencji programisty, np. walidacji pól w interfejsie użytkownika. Niemniej jednak wszystkie pozostałe obszary programu powinny być zabezpieczone przez mechanizm przechwytywania wyjątków. Podniesiony wyjątek musi zostać przechwycony (ang. catch), a następnie obsłużony. Każda aplikacja posiada zdefiniowaną strategię obsługi wyjątków. Tester ma obowiązek znać tę politykę. Wszelkie odchylenia od ustalonego standardu należy traktować jako błąd w kodzie. Strategia obsługi wyjątków musi być konsekwentnie wdrażana i kontynu­ owana dla nowych obszarów systemu. Równolegle z procesem weryfikacji wymagań biznesowych należy zbadać mechanizm przechwytywania wyjątków. Przechwycony wyjątek należy obsłużyć zgodnie z założeniami (realizacja kodu). Równie istotną kwestią jest prawidłowe logowanie (raport) incydentu do dziennika zdarzeń (plik logu). Obsługa i funkcjonowanie plików dziennika również leżą w po­ tencjalnym obszarze zainteresowań testera. Kontroler jakości powinien sprawdzić, czy incydent został odnotowany, oraz zweryfikować zawartość wpisu (wartość meryto­ ryczna). Kolejnym krokiem jest zwrócenie uwagi na czas przyrostu pliku. W przypadku kiedy logi przyrastają w szybkim tempie, należy pochylić się nad przyczyną tego stanu rzeczy. W dzienniku zdarzeń dane mogą być zapisywane w sposób podwójny (duplika­ ty), mogą być zbierane zbyt szczegółowe dane lub aplikacja może „rzucać wyjątkami” w bardzo krótkich odstępach czasu. Szybki wzrost rozmiaru plików może w niekon­ trolowany sposób skonsumować wolne zasoby pamięci masowej i obniżyć wydajność środowiska. Niedopuszczalną sytuacją jest przechwycenie wyjątku i zaniechanie dalszej jego ob­ sługi. Listing 1.7 prezentuje fragment kodu, w którym sekcja dotycząca obsługi wy­ jątku jest martwa. W takich okolicznościach w momencie wystąpienia sytuacji kry­ tycznej zostanie ona przejęta, ale operator nie zostanie o tym fakcie powiadomiony. Również nie zostanie odpowiednio zakończony proces biznesowy, tj. procedura wy­ kona się do końca, ale z błędami, które nie zostaną obsłużone. Niestety często zda­ rzają się skrypty, ba, nawet procedury, dla których obsługa wyjątku jest na minimalnym poziomie, tj. na takim, aby kompilator „przepuścił” kod. Listing 1.7. Błędna obsługa wyjątku w PL/SQL DECLARE BEGIN —L ogika commit; EXCEPTION WHEN OTHERS THEN —przechw ycenie wyjątku n u l l ; — brak obsługi wyjątku (logiki wyjątku) END;

Rozdział 1. ♦ Ogólna teoria testowania

45

Listing 1.8 prezentuje minimalną obsługę wyjątku na przykładzie języka PL/SQL, gdzie problem jest raportowany operatorowi. Stwarza to szansę do późniejszej analizy problemu. Listing 1.8. Minimalny poziom obsługi wyjątku na przykładzie języka PL/SQL s e t s e r v e r o u t p u t on; DECLARE BEGIN —L ogika e x e c u t e i mmedi at e ' s e l e c t * from t e s t @ d b l i n k ' ; d b m s _ o u t p u t . p u t _ l i n e ( ' B l o k wykonał s i ę p o p r a w n i e ' ) ; EXCEPTION WHEN OTHERS THEN —przechw ycenie wyjątku + raport problemu null; d b m s _ o u t p u t . p u t _ l i n e ( ' W y s t ą p i ł probl em - z b a d a j go: dbms_out put . put _l i ne( ' SQLERRM: ' | | SQLERRM); dbms_out put . put _l i ne( ' SQLCODE: ' | | SQLCODE);

');

end; /

Rysunki 1.13 oraz 1.14 prezentują efekt wykonania wcześniej przytoczonego kodu (listing 1.7 oraz listing 1.8) odpowiednio bez obsługi logowania wyjątków i z obsługą. Pierwsza próba zakończyła blok PL/SQL, ale nie wyświetliła informacji o problemie. Tester wykonujący kod może w pierwszej chwili mniemać, że procedura zadziałała poprawnie. Druga próba, która zrealizowana jest w oparciu o poszerzoną obsługę wyjątków (ponowne wykonanie kodu z udoskonaloną obsługą wyjątków), również zakończyła się poprawnym wykonaniem procedury przy jednoczesnym zwróceniu in­ formacji o problemie z łączem bazodanowym. Rysunek 1.13.

SQL>

Wykonanie kodu PL/SQL bez logowania wyjątków

SQL> set serveroutput on; SQL> DECLARE 2 3 BEGIN 4 5 — Logika 6 execute immediate 'select * from test@dbiink';

1 8 9

dbms_output.put_line('Blok wykonał się poprawnie'); EXCEPTION

10

11 12 13 14 15 16

WHEN OTHERS THEN — przechwycenie wyjątku + brakraportu null; end; /

PL/SQL procedure successfully completed SQL> I_____________________________________________________________

46

Testowanie oprogramowania. Podręcznik dla początkujących

Rysunek 1.14. Wykonanie kodu PL/SQL z logowaniem wyjątków

SQL> SQL> SQL> 2 3 4 5 6 7 8 9 10 11 12 13 14

15 16 17

set sexveroutput on; DECLARE BEGIN — Logika execute immediate 'select * from test0dblink'; dims output.put l i n e ('Blok wykonał się poprawnie')? EXCEPTION WHEN OTHERS THEN — przechwycenie wyjątki + raport problemu dbm3= output.put_line ( Wystąpił problem - zbadaj go: dbms_output.put_line('SQLERRM: ' Il SQLERRM);

dbms_output.put_line('5QLCQDE: ' Il 5QLCODE); end; /

Wystąpił problem - zbadaj go : SQLERRM: CRA-02019: nie znaleziono opisu połączenia dla odległej bazy danych SQLCODE: -2019 PL/SQL procedure successfully completed SQL>

Dojrzałe aplikacje oprócz strategii zarządzania wyjątkami wyposażone są w dedyko­ wany kod przechwytywania sytuacji niepożądanych w miejscach, które zostały uznane za wymagane. Kontrola jakości obejmuje również kod wyprodukowany do zadań specjalnych. Wy­ mownym przykładem są autonomiczne skrypty bazodanowe, które wykonywane są jednorazowo w celu migracji lub modyfikacji danych. Praca z dużym wolumenem da­ nych zawsze jest kłopotliwa i ryzykowna. Wystąpienie niespodziewanych sytuacji podczas wykonywania kodu jest niemalże pewne. Zatem skrypt powinien być odpo­ wiednio zabezpieczony przed spodziewanymi wyjątkami. Potwierdzenie implementacji obsługi wyjątków nie kończy pracy testera. Pozytywna opinia kontroli jakości może być wydana tylko wtedy, kiedy skrypt wykona się do końca, zrealizuje założenia biz­ nesowe, wszystkie wyjątki zostaną obsłużone oraz sposób ich obsługi będzie zgodny ze sztuką. Fakt wystąpienia wyjątku w fazie testowania nie oznacza niczego złego. Kluczowe jest, aby wszelkie incydenty były odpowiednio logowane i obsługiwane pod względem logicznym (zachowanie kodu w momencie podniesienia wyjątku). Prze­ chwytywane incydenty powinny być raportowane w sposób optymalny, to znaczy taki, który umożliwi dostateczną analizę sytuacji i podjęcie ewentualnych kroków napraw­ czych. Na miano „fuszerki” zasługują algorytmy, które po przechwyceniu wyjątku pomijają problem, tj. pracują dalej bez logowania i obsługi problemu (listing 1.7). Prawidłowo przygotowany skrypt wygeneruje listę problemów, która zostanie podda­ na szczegółowej analizie. Tester na podstawie zebranych danych może zbadać zaan­ gażowanie procentowe liczby wyjątków do pełnego wolumenu danych (odsetek błędów w stosunku do wszystkich przetwarzanych danych). Ów wskaźnik określi ryzyko i sku­ teczność skryptu. Zbyt duża liczba przechwyconych błędów może świadczyć o niskiej jakości kodu, niezrozumieniu wymagań, wadliwych danych.

Rozdział 1. ♦ Ogólna teoria testowania

47

Testowanie pod kątem obsługi wyjątków to również zadanie leżące w gestii kontrolera jakości. Zapewne programiści, którzy właśnie trzymają w ręku tę książkę, co najmniej lekko uśmiechają się pod nosem. „Co może wiedzieć tester o obsłudze wyjątku w pro­ gramowaniu”. Zapewne mniej niż programista. A co może wiedzieć programista o real­ nym wyniku pracy własnego kodu, skoro go nie uruchomił na uczciwych i rzeczywi­ stych danych? Mało efektywna obsługa i logowanie wyjątków przysporzy tylko kłopotów i zdaje się, że więcej ich przypadnie na osobę programisty niż na testera. Kontroler jakości uruchomi kod, stwierdzi błąd i go opisze, ale nie wskaże, w którym obszarze instrukcji jest problem i jaki jest aspekt merytoryczno-techniczny. W takich sytuacjach może nieco zelżeć dobry humor programisty, gdyż błąd jest ewidentny, a mate­ riał do podjęcia analizy jest skromny. Z dużym prawdopodobieństwem tester zostanie poproszony o ponowienie testu, tj. pomoc w odtworzeniu błędu. Niemniej jednak by­ wa, że powtórzenie testu jest utrudnione i czasochłonne ze względu na długą ścieżkę przygotowania lub „zepsucie” głównego wolumenu danych za pierwszym podej­ ściem. Oczywiście profesjonalny tester powinien być przygotowany na podjęcie dru­ giej próby, co równoznaczne jest z zabezpieczeniem środowiska pod kątem jednorazo­ wego wykorzystania danych, ale w ostatecznym rozrachunku przysparza dodatkowych kosztów pracy. Rozważmy poniższy przykład w celu uwiarygodnienia powyższych rozważań. Klient zamówił program, który wykona migrację danych teleadresowych z kartoteki klienta i numerów telefonów zamieszczonych w niej osób i dokona konsolidacji danych. Wspomniana konsolidacja polegać ma na przeniesieniu danych z dwóch do jednej tabeli przy uwzględnieniu ich reorganizacji, tj. połączeniu danych z kilku kolumn, dodaniu informacji „ekstra” i wstawieniu takiego ciągu do jednej z kolumn. Rysunek 1.15 pre­ zentuje opis trzech tabel, które posłużą do wykonania testu. Rysunek 1.15. Opis tabel wykorzystanych do testu migracji danych

SQL> desc TB_KARTOTEKA; Name

Type

Nullable Default Comments

ID NUMBER IMIE V A R C H A R 2 (100) NAZWISKO V A R C H A R 2 (100) ADRES

V A R C H A R 2 (200)

5QL> desc T3_KART0TEKA_N0WA; Name Type Nullable Default Comments ID IMIE NAZWISKO ADRES UWAGI

NUMBER V A R C H A R 2 (100) V A R C H A R 2 (100) V A R C H A R 2 (200) V A R C H A R 2 (200)

SQL> desc TB_KONTAKTY; Name Type ID NR_TEL

Nulla b l e Default Comments

NUMBER V A R C H A R 2 (20)

GODZ_KONTAK V A R C H A R 2 (50) Y O S T A T NI_KONTAK V A R C H A R 2 (20) Y SOL>_____________________________

48

Testowanie oprogramowania. Podręcznik dla początkujących

Dane z tabeli TB_KARTOTEKA oraz TB_KONTAKTY powinny być stosownie złączone i prze­ niesione do tabeli TB_KARTOTEKA_NOWA. Pozwolę sobie pominąć szczegółowy opis algo­ rytmu procedury, który można wyczytać z listingu 1.9. Niemniej jednak główny ciężar logiki skupia się na kolumnie UWAGI w tabeli TB_KARTOTEKA_NOWA. Do wskazanej kolumny powinny trafić dane: numer telefonu, preferowane godziny kontaktu, data ostatniego kontaktu, tj. sysdate minus liczba dni od ostatniego kontaktu, oraz ekstraopis według in­ strukcji IF (listing 1.9). Listing 1.9. KodPL/SQL, który odpowiada za migrację danych z logowaniem problemów s e t s e r v e r o u t p u t on; declare z1 t b _ k a r t o t e k a . i m i e % t y p e ; z2 t b _ k a r t o t e k a . n a z w i s k o % t y p e ; z3 t b _ k a r t o t e k a . a d r e s % t y p e ; b1 t b _ k o n t a k t y . n r _ t e l % t y p e ; b2 t b_ k o n t a k t y . g o d z _ k o n t a k %t y p e ; b3 t b _ k o n t a k t y . o s t a t n i _ k o n t a k % t y p e ; sql_stmt varchar2(200); t number := 1; a l ar m varchar2(50); cl varchar2(300); CURSOR k u r s o r i s select t.imie, t.nazwisko, t.adres, n.nr_tel, n.godz_kontak, n.ostatni_kontak from t b _ k a r t o t e k a t , t b _ k o n t a k t y n where t . i d = n . i d ; begi n OPEN k u r s o r ; LOOP FETCH k u r s o r INTO z l , z2, z3, b l , b2, b3; EXIT WHEN kur sor %not f ound; i f b3 > 60 t hen al ar m := ' K l i e n t wymaga p i l n e g o k o n t a k t u . Rano 8 - 1 0 , wi eczorem 19- 22. K l i e n t ^ j e s t bar dzo wymagający, z a d a j e dużo pyt ań i t r u d n o j e s t go z a c h ę c i ć do ^ z a k u p u . '; else al ar m := 'OK'; end i f ; c1

:= ' Nr t e l . : ' | | b1 | | ' | P r e f er owane godzi ny k o n t a k t u : ' | O s t a t n i k o n t a k t : ' | | ( s y s d a t e - t o_number ( b3) ) | | a l a r m;

' | | b2 | | ' | ' ||

Rozdział 1. ♦ Ogólna teoria testowania

49

s q l _ s t m t := 'INSERT INTO t b_ k a r t o t e k a _ n o wa VALUES ( : 1 , e x e c u t e i mmedi at e s q l _ s t m t us i n g t , z1, z2, z3, c l ; commit; t := t + 1; d bms_o ut put . put _l i ne( z1 | | END LOOP; CLOSE k u r s o r ;

' ' | | z2 | |

:2,

: 3,

: 4,

:5)';

' = OK' );

exception WHEN OTHERS THEN dbms_out put . put _l i ne( ' ===================' ) ; d b m s _ o u t p u t . p u t _ l i n e ( ' P o z o s t a ł e bł ę dy - r a p o r t ' ) ; d b m s _ o u t p u t . p u t _ l i n e ( ' P r o b l e m z k l i e n t e m : ' | | z1 | | d b m s _ o u t p u t . p u t _ l i n e ( 'SQLERRM: ' | | SQLERRM); dbms_out put . put _l i ne( ' SQLCODE: ' | | SQLCODE); dbms_out put . put _l i ne( ' ===================' ) ; end;

' ' ||

z2);

Rysunek 1.16 przedstawia wynik zapytania SQL pobranego bezpośrednio z kursora procedury oraz wynik pobrania danych z nowej tabeli, do której zostały przeniesione dane po wykonaniu powyższego zestawu instrukcji. SQL>

s e l e c t c o u n t (t.imię)

f r o m t b _ k a r t o t e k a t,

tb_kontakty n where

t . i d = n.i d ;

C O U N T (T.IMIE) 4 SQL> select

c o u n t (*)

from tb_kartoteka_nowa;

C O U N T £*) 3 5 Q L > __________________________________________________________________________________________________

Rysunek 1.16. Wynik zapytania SQL z kursora oraz pobranie danych z tabeli docelowej Przyglądając się dokładnie, nietrudno dostrzec, że kursor wybrał 4 wiersze, a tylko 3 zo­ stały wstawione do tabeli migracyjnej. Zatem coś musiało się stać, gdyż jeden wiersz został pominięty. Z kodu nie wynika, aby dane pobrane do kursora podlegały dodat­ kowej selekcji przed migracją. Rysunek 1.17 przedstawia wynik wykonania procedury z listingu 1.9, ale bez logowania wyjątków. Ewidentnie operator skryptu nie ma podstaw podejrzewać, że wystąpiły trudności, gdyż nie otrzymał żadnego sygnału „z kodu”. Rysunek 1.18 pokazuje rezultat wykonania tego samego kodu, ale wzbogaconego o in­ strukcje logowania problemów. W tym przypadku oprócz raportu poprawnie przenie­ sionych klientów operator otrzymuje relację o zaistniałych „po drodze” problemach. Omawiany przykład zawiera sztucznie spreparowany (założony) błąd polegający na tym, że dla jednego klienta zostanie przekroczony zakres pola. Takie sytuacje mogą często występować w momencie przepisywania danych przy jednoczesnym łączeniu

50

Testowanie oprogramowania. Podręcznik dla początkujących

Rysunek 1.17.

55

Rezultat wykonania kodu bez logowania błędów

exception

56 57

W H E N OTHERS THEN null;

58

end;

59

/

Adam_3 Kowalski_3 = OK Adair._4 K o w a l s k i _ 4 = O K Adam Kowalski — OK PL / S Q L p r o c e d u r e s u c c e s s f u l l y c o m p l e t e d S Q L > s e l e c t c o u n t (*)

f r o m tb k a r t o t e k a nowa;

C O U N T (*) 3

I Rysunek 1.18. Rezultat wykonania kodu z logowaniem błędów

55 56 57 58 59 60 61 62 63 64

exception WHEN OTHERS THEN dbms_output .put_line (' -------------------') ; dbms output.put l i n e (1Pozostałe błędy - raport'); dbms_output.put_line('Problem z klientem: ' | | Z1 dbms_output.put_line('SQLERRM: ' || SQLERRM); dbms_output.put_line(1SQLCODE : 1 || SQLCODE); dbms_output.put_line('===================■);

|| ' ' I I z2);

end; /

Adam_3 Kowalski_3 = OK Adam_4 Kowalski_4 - OK Adam Kowalski = OK Pozostałe błędy - raport Problem z klientem: Adam_2 Kowalski_2 SQLERRM: ORA-06502: PL/SQL: błąd liczby lub wartości: SQLCODE: -6502

za mały bufor tekstowy

PL/SQL procedure successfully completed 5QL> I______________________________________

ich oraz dopisywaniu jakichś danych według algorytmu. Programiście jest bardzo trudno przewidzieć wszystkie sytuacje. Skuteczność kodu weryfikowana jest w trak­ cie jego użycia na dużym wolumenie danych o jakości zbliżonej do rzeczywistych. Przyzwoite przechwytywanie wyjątków i logowanie problemów stanowi podstawę do ewentualnych modyfikacji kodu i uskuteczniania założonego celu.

Rozdział 1. ♦ Ogólna teoria testowania

51

1.11. Narzędzia wsparcia pracy testera Tester oprogramowania w celu poprawienia efektywności, skuteczności oraz miaro­ dajności testów wspomaga się szeregiem narzędzi, którymi uskutecznia czynności. Poniżej przedstawiam listę (niezbędnik) narzędzi osobistego wsparcia pracy testera: SoapUI — narzędzie umożliwiające testowanie usług sieciowych (web service). Strona domowa projektu: http://www.soapui.org/. Notepad++ — edytor tekstu z podświetlaniem składni języka programowania; http://notepad-plus-plus.org/.

NetBeans IDE — środowisko programistyczne; https://netbeans.org/. Eclipse — środowisko programistyczne; http://www.eclipse.org/. Apache JM eter — narzędzie do przeprowadzania testów wydajnościowych, obciążania systemu, np. bazy danych, web service czy stron WWW; http://jmeter.apache.org/. Fiddler2 — lokalne proxy wykorzystywane np. do debugowania stron WWW; http://fiddler2. com/.

Firebug — wtyczka do Firefoksa pozwalająca np. na debugowanie stron; http://getfirebug. com/.

TCPM on — monitor TCP (bez obsługi SSL); http://ws.apache.org/tcpmon/. M em brane M onitor — monitor HTTP i SOAP; http://www.membrane-soa.org/soap-monitor/.

W ireshark — analizator ruchu sieciowego; http://www.wireshark.org/. VNC — narzędzie do zdalnego logowania, np. http://www.realvnc.com/. PL/SQL Developer, TOAD — klient bazy danych. W inSCP — klient z interfejsem graficznym SFTP, FTP; http://winscp.net/eng/ docs/lang:pl.

PuTTY — klient SSH; http://www.putty.org/. G eneratory certyfikatów SSL (KeyStore) — np. KeyStore Explorer. G eneratory sumy kontrolnej — np. dla algorytmów SHA1 i MDA5; http://onlinemd5. com/.

M enedżer plików — np. Total Commander przydatny przy przeszukiwaniu zasobów i porównywaniu zawartości plików etc. Narzędzia do robienia zrzutów ekranu (Prnt Scrn) — rynek oferuje liczne aplika­ cje o różnym stopniu zaawansowania. Każdy z pewnością znajdzie odpowiedni pro­ gram dla siebie.

52

Testowanie oprogramowania. Podręcznik dla początkujących

Edytory tekstu — niezbędne do sporządzania dokumentacji z przeprowadzonych testów. Arkusze kalkulacyjne — wykorzystywane np. do obliczeń manualnych według algo­ rytmu (sprawdzenie wyniku logiki systemu), generowanie danych testowych. Em ulatory — zadaniem tego rodzaju oprogramowania jest „udawanie” innego pro­ gramu, urządzenia lub jednej z funkcji innego systemu. Przykładem oprogramowania symulującego działanie mobilnej wersji przeglądarki Opera jest Opera Mobile Emu­ lator. Nadmieniony emulator umożliwia wykonanie pretestów aplikacji dedykowanych na urządzenia mobilne na tradycyjnych desktopach. W alidatory — np. walidator wyrażeń regularnych. Program y do identyfikacji i zmiany kodowania znaków w pliku Serwer poczty (SMTP/POP3/IMAP), który można skonfigurować lokalnie — np. hMailServer; http://www.hmailserver.com/. Narzędzia do automatyzacji testów — np. Oracle OpenScript (http://www.oracle.com), SoapUI, Apache JMeter, Selenium (http://www.seleniumhq.org/). G eneratory danych testowych — np.: http://www.generatedata.com/.

1.12. Presja czasu Na pierwszych kartach publikacji poruszyłem przykry aspekt postrzegania działu te­ stów jako czynnika blokującego, a nawet opóźniającego wydanie wersji oprogramo­ wania klientowi. Projekt jest przedsięwzięciem, które osadzone jest w ściśle zdefi­ niowanych ramach czasu. Posiada początek i koniec. Data końca projektu stanowi punkt krytyczny, którego przekroczenie, tj. niewykonanie zadania w terminie, zwykle niesie za sobą znaczne konsekwencje. W ostatecznej formie owe konsekwencje mogą objawić się poprzez pogorszenie wyniku finansowego, co nigdy nie ujdzie uwagi najwyższych władz w przedsiębiorstwie. Problem, skutek, wina, kara. To cztery kroki zwykle podejmowane po „obsuwie” terminu lub całkowitym „położeniu” projektu. Faktem oczywistym jest, że nikt nie chce dopuścić, aby wspomniany scenariusz się ziścił. Etap kontroli jakości stanowi ostatnie ogniwo w procesie produkcji oprogra­ mowania. Zatem zespół testów narażony jest na niebywałą presję, której efektem ma być wydanie oprogramowania w terminie. Oczywiście zamknięcie projektu w terminie bez uszczerbku na jakości finalnego produktu. Przyjrzyjmy się rysunkowi 1.19. Niezależne testy jakościowe, tj. takie, które odbywają się w autonomicznym środowisku (innym niż deweloperskie), faktycznie rozpoczęły się ze znacznym opóźnieniem w sto­ sunku do planowanego harmonogramu. Faza programowania została zakończona w momencie, w którym powinny już odbywać się ostateczne testy jakościowe (punkt B). Testy modułowe w wyniku opóźnienia implementacji również zakończono znacznie później. To bardzo niekomfortowa sytuacja dla zespołu testów jakościowych. W oczach PM projekt ma jeszcze kilka dni na osiągnięcie gotowości. Niemniej jednak w rze­ czywistości przy zachowaniu planowanego wysiłku testów (intensywności) nie ma

Rozdział 1. ♦ Ogólna teoria testowania

53

Przebieg p la n o w a n y

u W N

Analiza

Testy

N iezależne te s ty

w e w n ę trz n e

jakościow e



1

P ro je k to w a n ie

1

0

Kodow anie

>

Przebieg

>

P ro je k to w a n ie

1

Analiza

K o dow anie

\

1

Testy

N iezależne testy

w e w n ę trz n e

jakościow e

^

■!1

A

B

1

Oś czasu p ro jek tu ---------------------------- --------------------- -— £ 0

Kary um o w n e ►

C

Rysunek 1.19. Hipotetyczny przebieg realizacji projektu produkcji oprogramowania realnej szansy na zakończenie go w terminie. Niestety racje i argumenty zespołu testów nie mają szans przebicia się przez strach i widmo konsekwencji przesunięcia daty koń­ cowej projektu. Oprogramowanie ma zostać wydane w terminie! Co to oznacza dla kontroli jakości? Problem! Wykonanie założonego planu testów w skonsolidowanym oknie czasu, tj. wykonanie zakresu testów rozpisanego np. na 12 dni w 5. Zważyć należy na brak zwolnienia z odpowiedzialności za jakość. Ugięcie się pod naciskami PM nie gwarantuje rozgrzeszenia w przypadku pogorszenia jakości. Niemniej jednak jeżeli zapadnie decyzja o wydaniu produktu w planowanym terminie, należy zintensy­ fikować wysiłek testerski i przeprowadzić maksymalnie wiele założonych testów (ry­ sunek 1.20). Przebieg p la n o w a n y

P ro je k to w a n ie

Analiza

K o dow anie

Testy

N iezależne te s ty

w e w n ę trz n e

jakościow e

|

Przebieg rzeczyw isty

P ro je k to w a n ie

Analiza

1

_

N iezależn e te s ty

K odow anie

i

i

Oś czasu p ro je k tu -

U

1 ..

L .

| 1

Z w ie lo k ro tn ie n ie p lan o w an eg o w ysiłku na e ta p ie te s tó w jakościow ych

P ro je k to w a n ie

K o dow anie

i

Kary u m o w n e ►

B

A naliza

k

jakościow e

Testy w e w n ę trz n e H

Rysunek 1.20. Zwiększenie intensywności testów, tak aby dotrzymać terminu dostawy

54

Testowanie oprogramowania. Podręcznik dla początkujących

Intensyfikacja procesu testów jest często stosowaną praktyką w celu dotrzymania terminu dostawy lub minimalizowania strat. Zwykle jest to rozsądna i dobra droga, choć obarczona wadami i ryzykiem. Wzmożenie wysiłku wymaga zaangażowania dodatkowych osób i/lub zwiększenia zaangażowania już pracujących przy projekcie. Nowe osoby wymagać będą wprowadzenia do roli i z pewnością nie będą „czuły” oprogramowania w takim samym stopniu jak osoby pracujące od początku. Niesie to ze sobą ryzyko przeoczenia błędów, które z dużym prawdopodobieństwem zostałyby wykryte przy normalnym przebiegu ścieżki testów. Zmęczenie również nie pozostaje bez skutku na percepcję, a wydłużenie godzin pracy sprzyja zmniejszeniu sprawności testera. Niemniej jednak przy uwzględnieniu korzyści i ryzyka bilans takowego roz­ wiązania można uznać za dodatni. Kluczem do sukcesu jest, aby wyj ątek nie potwierdzał reguły. Równomierne obciążenie pracą sprzyja efektywności i skuteczności testów. Po intensywnym, lecz krótkotrwałym wysiłku powinien nastąpić okres regeneracji. Niewskazane jest obciążanie testera „nową akcją ratunkową” już w kolejnym dniu po świeżo zamkniętym projekcie. Więcej in­ formacji o aspektach zmęczenia pracą zamieściłem w rozdziale poświęconym „syndro­ mowi zniechęcenia testami”. Kolejna prawda o testowaniu brzmi: Nie istnieje opcja zwolnienia działu testów z od­ powiedzialności za ostateczną jakość produktu.

1.13. Profil profesjonalnego testera Praca w charakterze testera oprogramowania może dostarczyć wiele satysfakcji, lecz także wymaga pewnych predyspozycji, umiejętności i zaangażowania w powierzone zadania. Jest to praca odpowiedzialna i specyficzna pod względem wymagań stawianych potencjalnym kandydatom. Z jednej strony pożądany jest szereg kompetencji twardych, z drugiej strony równie istotne są umiejętności społeczne. Kompetencje twarde, np. umiejętność czytania kodu JAVA, stanowią podstawę do wykonywania powierzonych zadań. Praca testera oprogramowania wymaga szerokich umiejętności twardych, ale niekoniecznie głęboko wnikających w dany aspekt. Pożą­ dane jest, aby tester potrafił czytać kod, przygotować własne fragmenty instrukcji, ale nie musi on posiadać równie biegłej umiejętności programowania co koderzy. Analo­ giczne podejście można zastosować do ogółu technologii zastosowanych w architekturze systemu i jego kodzie. Warto znać serwer bazy danych, ale nie trzeba już się mar­ twić o wiedzę z zakresu strojenia i administracji. Zgoła inaczej sytuacja wygląda w kwe­ stii umiejętności posługiwania się narzędziami stricte testerskimi, np. SoapUI, JMeter, OpenScript. Aplikacje poddawane testowaniu mogą dotyczyć najróżniejszych dzie­ dzin życia, które czasami okazują się zupełnie obce dla testera. Zatem szeroka wiedza ogólna jest niezmiernie ważna, aby prawidłowo wykonywać testy, tj. rozumieć apli­ kację. Reasumując: tester powinien dysponować ugruntowanymi umiejętnościami twardymi ściśle związanymi z wykonywaniem testów i np. specjalistycznymi narzę­ dziami, mieć szeroką wiedzę ogólną oraz znać w przynajmniej podstawowym zakresie zastosowane technologie. Szczegółowe testy niefunkcjonalne, np. wydajnościowe, mogą wymagać większego zainteresowania się aspektami technologicznymi, np. zgłębienia za­ sad działania i możliwości serwera bazy danych.

Rozdział 1. ♦ Ogólna teoria testowania

55

Pożądane kompetencje twarde w pracy testera oprogramowania (ogólne ujęcie minimum): ♦ umiejętność czytania kodu, podstawy programowania (np. w celu napisania robota generującego dane i zasilania nimi bazy); ♦ znajomość narzędzi wspomagających testy, np. SoapUI, JMeter, klient serwera bazy danych, Fiddler, OpenScript, środowiska programistyczne, np. Eclipse, itp.; ♦ znajomość wykorzystywanych technologii, np. serwer WWW, serwer bazy danych, system operacyjny, np. Android; ♦ znajomość szeregu technologii pobocznych do głównego nurtu wykonania aplikacji, np. XML, SOAP, REST, CSS, HTTP itp.; ♦ umiejętność obsługi urządzeń końcowych, np. nawigacji GPS, urządzeń mobilnych (sprzęt, na którym uruchamiane jest oprogramowanie); ♦ znajomość narzędzi do zarządzania testami i raportowania błędów; ♦ umiejętność projektowania i wykonywania testów; ♦ wiedza z zakresu metodyki testowania; ♦ wiedza z zakresu projektowania i wytwarzania oprogramowania, np. podstawowa znajomość wzorców projektowych; ♦ wiedza z obszaru, jakiego dotyczy oprogramowanie, np. telekomunikacji, gastronomii itp. Wbrew pozorom zbyt bogate kompetencje z zakresu jednej technologii mogą prze­ szkadzać w wykonywaniu testów funkcjonalnych. Należy pamiętać, że końcowi użyt­ kownicy zwykle nie mają żadnej wiedzy technicznej i skupiają się jedynie na użytko­ waniu systemu. Wydatnym przykładem są sytuacje, w których programiści podejmują się pracy w roli testera oprogramowania. Trudność polega na tym, że nie są oni zwykle w stanie porzucić myślenia programistycznego i analizowania funkcjonalności po­ przez wyobrażanie sobie kodu. Zbyt daleko idąca wnikliwość w aspekty techniczne może przesłonić istotne problemy funkcjonalne, np. no tak, inaczej nie mógł tego zrobić. Może mógł, może nie. Wątpliwość powinna być zgłoszona i poddana analizie, może udałoby się wypracować jakieś lepsze rozwiązanie. Dochodzimy do momentu, w którym należy postawić pytanie: Czy programista może być dobrym testerem oprogram owania?. W mojej opinii nie. Nie wynika to z braku chęci czy kompetencji technicznych, ale z naleciałości, jakie odziedziczył podczas pracy w dziale deweloperskim. Owo dziedzictwo zwykle nie stanowi wartości doda­ nej, lecz stanowi przeszkodę w odnalezieniu się w roli testera. Czy tester może być dobrym programistą? Może, ale to jest bilet w jedną stronę. Doświadczenie zdobyte w testach może wpłynąć na rozwiązania zastosowane w kodzie z uwagi na to, że świeżo upieczony programista oczami wyobraźni widzi efekt działania kodu i może wyczuwać pewne problemy. Natomiast dużą przeszkodą może okazać się brak doświadczenia w programowaniu. Tegoż elementu nie da się nadrobić w krótkim czasie. Z jednej strony doświadczenie w testach pozwoli uniknąć pewnych błędów funkcjonalnych, a z drugiej strony brak doświadczenia w programowaniu spowoduje intensyfikację typowych błę­ dów programistycznych (np. składnia kodu).

56

Testowanie oprogramowania. Podręcznik dla początkujących

Kompetencje psychospołeczne są równie istotne jak doświadczenie i wiedza meryto­ ryczna. Umiejętności miękkie są niezwykle ważne w trakcie wykonywania powierzo­ nych zadań w zawodzie testera oprogramowania. Tester musi skutecznie radzić sobie ze stresem, efektywnie zarządzać czasem, wykazywać się elastycznością w działaniu, mieć inicjatywę, współpracować w grupie oraz sprawnie komunikować się. Niektóre z umiejętności interpersonalnych, np. empatia, życzliwość, zdolności komunikacyjne, ułatwiają kształtowanie pozytywnych relacji z pozostałymi członkami zespołu. Równie istotne są cechy, które odpowiadają za budowanie społecznej pozycji testera, takie jak pewność siebie, umiejętność pokonywania trudności, zdolność do prezentacji i obrony poglądów, asertywność. Umiejętności miękkie należy nieustannie rozwijać i pielęgno­ wać. Wydawać by się mogło, że zawód informatyka nie wymaga nadzwyczaj rozwi­ niętych wyżej wymienionych zdolności. Praca testera wymaga innowacyjności, dynamiki w działaniu, kooperacji. Istotą pracy testera jest weryfikacja jakości oprogramowania. Można by więc powiedzieć, że powinien usiąść i „przeklikać” aplikację, zakończyć zadanie i przekazać produkt. Kłam temu podejściu zadaje szereg czynności pobocz­ nych, które tester musi wykonać, aby właściwie zrealizować powierzone zadanie. Prawdą jest, że samo wykonanie testu opiera się głównie na kompetencjach meryto­ rycznych. Niemniej jednak zanim do tego dojdzie, tester z reguły musi zmierzyć się z szeregiem problemów, których przezwyciężenie wymaga wysoko rozwiniętych kom­ petencji społecznych. Przytoczę poniżej kilka sytuacji (przykładów), które powinny uwiarygodnić powyż­ szy wywód. ♦ Tester powinien wykazać się innowacyjnością i kreatywnością np. na potrzeby symulacji błędu albo opracowania specyficznego scenariusza testów (łamanie szablonów). ♦ Tester powinien potrafić publicznie wygłaszać swoje opinie, uzasadniać je oraz bronić ich w sytuacji, kiedy uzna, że coś działa wadliwie lub może nie spełniać oczekiwań klienta. Niepożądane jest przystawanie na propozycje, które nie są poparte żadnymi argumentami, typu „tak zrobiłem i tak zostanie”. ♦ Tester powinien poczuwać się do współodpowiedzialności za produkt i nie ulegać presji (socjotechnika współpracowników). Wszelkiej maści naciski ujawniają się w momencie zagrożenia terminu. ♦ Tester powinien rozumieć uczucia innych, ale nie na zasadzie wyrzeczenia się dobrych praktyk i standardów. Porozumienie zawsze jest możliwe. Niemniej jednak nie można pracować jako kontroler jakości w poczuciu, że wykonuje się gorszą pracę niż programista czy projektant. ♦ Tester bardzo dużo rozmawia i komunikuje się z klientem wewnętrznym i zewnętrznym. Zatem niezmiernie ważne są zdolności komunikacyjne, poczucie humoru, konsekwencja i śmiałość. ♦ Niezmiernie ważne jest zachowanie wyważonej asertywności, tak by nie zaburzyć równowagi pomiędzy chęcią pomocy innym a byciem wykorzystywanym. Idealny zespół testerów to taki, w którym wszyscy członkowie dysponują zróżnico­ wanym poziomem poszczególnych kompetencji miękkich. Oczywiście punktem wyj­ ścia jest spełnienie ogólnie zdefiniowanych wymagań minimalnych (kompetencje

Rozdział 1. ♦ Ogólna teoria testowania

57

twarde i miękkie). Niemniej jednak u podstaw siły zespołu leży zróżnicowanie umie­ jętności interpersonalnych. Projekty są różnorodne pod względem złożoności tech­ nologicznej, trudności merytorycznej, potrzeb komunikacji i specyfiki testów. Osoby odgrywające wiodącą rolę w projekcie powinny być dobierane pod względem predyspo­ zycji, które są kluczowe do zrealizowania zadań. Osoby, które są niezmiernie skrupu­ latne, potrafią długotrwale pracować nad jednym zadaniem, idealnie odnajdą się w za­ daniach testowych wymagających żmudnej, długotrwałej pracy, zanim osiągnie się ostateczny rezultat. Jednostki mniej cierpliwe mogą próbować iść na skróty i pominąć kilka ważnych kroków, które mogą okazać się istotne w aspekcie jakości oprogramo­ wania. Z kolei projekty wymagające wytężonego wysiłku — nazwijmy to negocjacyj­ nego — nie powinny być powierzane osobom zbyt nieśmiałym, uległym i szybko się irytującym (w roli lidera). Efektywne zarządzanie projektem wymaga, aby przy każdym nowym przedsięwzięciu formować grupę według predyspozycji i zadań. Dobrze dobrany zespół połączony administracyjnie zwykle dysponuje odpowiednim potencjałem do utworzenia grupy niejako uszytej na miarę projektu. Ktoś, kto jest liderem w projekcie A, w kolejnym przedsięwzięciu B może odgrywać inną rolę, co nie oznacza, że mniej ciekawą i mniej odpowiedzialną. To jest kolejna cecha, jaką powinien wykazywać się tester. Miano­ wicie elastyczność i łatwość w dostosowywaniu się do nowych ról. Osoby pyszne, władcze i czułe na krytykę będą miały trudności w podejmowaniu działań w roli wy­ konawcy zadań (bez wpływu na elementy organizacyjne). Praca testera może być postrzegana jako zbędny generator kosztów, gdyż w mniemaniu zarządzających w wyniku owego procesu nie powstaje żadne wymierne dobro (pro­ dukt). Wiadomo, programista koduje i na zakończenie pracy „zostawia” aplikację. A te­ ster? Cóż, siedzi, czepia się, stuka w klawiaturę, marudzi i w dodatku nie pozwala na przekazanie aplikacji klientowi (czytaj: sprzedaż). Na szczęście ten wielce niesprawiedliwy trend ulega odwróceniu. Doświadczeni testerzy są bardzo cenieni na rynku pracy. Producenci oprogramowania dostrzegają związek pomiędzy wysoką jakością swoich produktów a realnym przełożeniem tego wskaźnika na renomę i długofalowy sukces firmy. Tester to osoba, która dokonuje pierwszego uruchomienia aplikacji, nowego modułu wnoszącego dodatkowe funkcjonalności do systemu. Sprawdza również zgodność implementacji z wymaganiami klienta w oparciu o dostarczoną dokumentację. To tester jest osobą, która decyduje o uznaniu aplikacji za zdatną do przekazania klientowi. Tester sprawdza, czy analiza, projekt oraz jego implementacja mają rację bytu w rzeczy­ wistości. Jest takie powiedzenie „papier przyjmie wszystko”, ale klient już tego nie uczyni w odniesieniu do gotowego produktu. Certyfikaty i szkolenia Profesja testera oprogramowania znajduje coraz mocniejsze uznanie wśród osób, któ­ re są w przededniu wyboru zawodu, swojej ścieżki kariery. Analizując oferty pracy, można dostrzec, że specjaliści w tej dziedzinie są coraz bardziej poszukiwani i doce­ niani. Trudno wyobrazić sobie proces wytwarzania oprogramowania, w którym nie re­ alizuje się jego weryfikacji pod względem jakości. Obecnie testowanie oprogramowania wymaga zaangażowania osób o ściśle pożądanych kompetencjach miękkich i twardych.

58

Testowanie oprogramowania. Podręcznik dla początkujących

Nie mogą to być ludzie przypadkowi, którzy nie do końca mają zamiar utożsamiać się z tym zawodem. Profesjonalny tester oprogramowania powinien legitymować się przynajmniej podstawowym certyfikatem ISTQB (http://www.istqb.org/). Płyną z tego dwie korzyści. Po pierwsze: taki dokument uwiarygodnia jednostkę w oczach pra­ codawcy. Po drugie: zwiększa jej szanse na rynku pracy. Merytoryczna wartość do­ dana z ukończenia owego kursu jest kwestią dyskusyjną. Można by polemizować, na ile treść kursu może być przeniesiona na warunki realne. Niemniej jednak ten certy­ fikat nie niesie ze sobą nic negatywnego. Systemy informatyczne stają się coraz bardziej skomplikowane i wyrafinowane. Często szyte są na miarę potrzeb poszczególnych organizacji. Wymaga to od testera dużego zaangażowania merytorycznego. Zatem niezmiernie ważne jest odbywanie regular­ nych szkoleń technicznych, np. z narzędzi wspomagających testy i technologii, w której wytwarzane jest oprogramowanie. Rzecz jasna kluczem jest świadomość konieczno­ ści samokształcenia się i doskonalenia własnych kompetencji również samodzielnie. Anegdota N ie g d yś m ia łe m o k a z ję u c z e s tn ic z y ć w s z k o le n iu p o św ię co n ym te s to w a n iu o p ro g ra m o w a n ia . T re n e r w yra ził tw a rd ą o p in ię , że te s te r je s t w s ta n ie zw e ryfikow ać każde o p ro g ra m o w a n ie , o ile m a s to s o w n ą do te g o d o k u m e n ta c ję . W m o je j o c e n ie to s tw ie rd z e n ie n ie je s t p ra w d ziw e . Rzeczą o c z y w is tą je s t , że d o ś w ia d c z o n y te s te r m oże z w e ry fik o w a ć w ie le różn ią cych s ię od s ie b ie a p lik a c ji, ale nie w szystkie . T rudno m i s o b ie w yobrazić, aby kto ś, kto nie m a n a jm n ie j­ szego p o ję c ia o lo tn ic tw ie , k o le jn ic tw ie , m e d y c y n ie lu b k o s m o n a u ty c e , m ó g ł p rze p ro w a d zić te s ty de d ykow an e g o o p ro g ra m o w a n ia tylko w o p a rciu o otrzym a n ą d o ku m e n ta c ję . Z ałóżm y, że o trz y m a m y do w e ry fik a c ji p ro g ra m s łu ż ą c y do k o ryg o w a n ia tra je k to rii lo tu p o c is k u b a lis ty c z ­ nego. S ia d a m y, bierzem y do ręki s e tk i, ty s ią c e stro n d o k u m e n ta c ji z w zoram i i o p is e m ... i co d a le j? O czyw iście to s ą s k ra jn e ro zw a ża n ia . Dążę do te g o , aby p o w ie d z ie ć , że is tn ie ją pe w ­ ne o b s z a ry , pew n e o p ro g ra m o w a n ie , do te s tó w któ re g o w ym a g a n a je s t n a le żyta p o d s ta w a m e ry to ry c z n a , tz n . „ p o z a te s te rs k a " . W a ru n k ie m ko n ie c z n y m je s t ro z u m ie n ie te g o , co s ię ro b i, o ra z p o czu cie s e n s u i is to ty o b s z a ru , któ re g o do tyczy o p ro g ra m o w a n ie . W s p o m in a m o ty m , aby p rze strze c przed zbytnią w ia rą w e la s ty c z n o ś ć pracy ja k o te s te r, gdyż m oże być to zgubne d la s a m e g o te s te ra i d la o p ro g ra m o w a n ia . P rzystosow anie do te s tó w now ego syste m u m oże być b a rd zo ła tw e , cza se m n ie c o b a rd zie j w y m a g a ją c e lub w rę cz s z a le n ie tru d n e .

1.14. Testowanie w oknie czasu Czas jest elementarnym składnikiem organizacji życia społecznego, zatem odgrywa on również istotną rolę w procesie wytwarzania oprogramowania. Wiemy już, że sam projekt jest osadzony w ramach czasu, tj. ma początek i koniec. Niemniej jednak w tym rozdziale zastanowimy się nad aspektami czasu w funkcjonującej produkcyjnie aplikacji. Czasami stosuje się zabieg, w którym z premedytacją przerywamy proces po upływie ściśle zdefiniowanego czasu (ang. time out). Ograniczenie czasu dla danego zdarzenia pozwoli uniknąć sytuacji nieskończonego oczekiwania na odpowiedź, a w konsekwencji blokady procesu. Drugim klasycznie stosowanym przykładem jest wylogowanie użyt­ kownika z systemu po upływie określonego czasu bezczynności. Oczywiście jest to robione z uwagi na względy bezpieczeństwa i poniekąd nie ma potrzeby utrzymywania

Rozdział 1. ♦ Ogólna teoria testowania

59

„martwych” sesji. Są to przypadki kiedy to my, tj. nasza aplikacja, sterujemy czasem. Testy powyższych założeń nie powinny sprawić wielkich trudności. Sytuacja diametralnie ulega komplikacji w przypadku, kiedy zainicjowany proces bezwzględnie musi zakończyć się w założonym oknie czasu, np. trwać od 22:00 do 23:35, tj. 01:35 minut. Wspomniane założenie nie może podlegać żadnym formom uelastycznienia z uwagi na to, że na przykład o godzinie 23.40 rozpoczyna się kolejny proces, który korzysta z wyników pracy pierwszego. Ten drugi proces powinien zakoń­ czyć się przed 23.55, bo o godzinie 00:00 następuje „przejście przez dzień” i „wszystko zaczyna się od początku”. Testy takich procesów mogą okazać się kłopotliwe i nie zawsze uda się ocenić w pełni skuteczność zmian. Główną przeszkodą jest brak po­ równywalnych zasobów sprzętowych (serwerów) oraz wolumenu danych (nie tylko ilość, ale i jakość). Przetwarzanie porównywalnego zakresu danych w środowisku testo­ wym może trwać znacznie dłużej niż analogiczna czynność procesowana w środowisku docelowym. Nadmieniłem, że jest to związane z różnicami w potencjale obliczeniowym obydwu środowisk oraz specyficznej konfiguracji np. serwera bazy danych. Ostateczne testy zapewne będą odbywać się w środowisku docelowym przy współpracy z klien­ tem. Niemniej jednak zanim zostanie wykonana taka próba, należy poczynić trud wstęp­ nej weryfikacji w oparciu o zasoby działu testów. Po pierwsze: tester może zweryfi­ kować, czy logika biznesu działa prawidłowo. Po drugie: można zbadać, czy założenia odgrywające kluczową rolę dla wydajności, np. ilość powołanych wątków w przetwa­ rzaniu, funkcjonują. Po trzecie: można spróbować sztucznie napełnić danymi system i uruchamiać procesy na podwyższonej ilości danych. Jeżeli jest to modyfikacja wy­ dajnościowa już istniejącego rozwiązania, warto sprawdzić, czy nowe podejście nie działa gorzej, np. wolniej, od dotychczasowego, na identycznym zestawie danych (okolicznościach). Zapewne będzie trudno odnotować zauważalną poprawę wydajno­ ści, gdyż w dużych systemach takie zmiany projektuje się bezpośrednio pod środowisko docelowe, ale jeżeli się nie pogorszy i biznes będzie funkcjonował poprawnie, można rozpocząć przygotowania do weryfikacji w środowisku ostatecznym. Kolejnym utrudnieniem w trakcie wykonywania testów są ograniczenia aplikacji w po­ staci używania pewnych funkcji w określonym czasie i dacie, np. ograniczenie tylko do bieżącej daty lub przetworzenie danych jedynie do dwóch dni wstecz itp. Nie zawsze istnieje możliwość manipulowania datami i czasem w testach. Takie okoliczności zmuszają do skrupulatnego planowania testu, tak aby nie stracić szansy na zweryfikowa­ nie wyniku — np. inicjalizujemy jakiś proces, który zostanie automatycznie dokoń­ czony w nocy, a wynik prezentowany w raporcie — kolejnego dnia. Bywa, że w sposób bezpieczny można podrasować środowisko testów, tak aby pewne ograniczenia zdjąć. Niemniej z takich trików należy korzystać z najwyższą ostrożnością. Nadmierne uela­ stycznianie systemu na potrzeby testów może być zgubne, gdyż sztucznie poszerzone możliwości systemu po pewnym czasie mogą „wejść w krew” i zostać przez zespół testów traktowane jako normalna cecha aplikacji produkcyjnej. Wykonywanie testów „na skróty” niesie ryzyko przepuszczenia istotnych błędów, które miałyby szanse zostać wykryte w trakcie wykonywania „uczciwej” ścieżki.

60

Testowanie oprogramowania. Podręcznik dla początkujących

1.15. Jak wygląda realizacja projektu w praktyce? Najwięcej trudności w trakcie realizacji projektu IT nastręcza różnica w interpretacji i zrozumieniu oczekiwań biznesowych. Często się zdarza, że jeden zapis interpretowany jest zgoła odmiennie przez każdą z zainteresowanych stron.. Ciekawym zjawiskiem jest, że dla każdego jego interpretacja jest właściwa. W praktyce poszczególni zaintere­ sowani, np. programista, tester, klient, mogą uznać, że wykonali pracę solidnie i zgod­ nie z oczekiwaniem, a finalnie wystąpią np. problemy z integracją aplikacji z innym systemem lub wdrożone rozwiązanie nie zaspokaja rzeczywistych potrzeb zamawiają­ cego. Wszystko to teoretycznie zgodnie z zapisami! Bardzo lubię przy okazji powyższych rozważań przytaczać piktogramy udostępnio­ ne w projekcie How IT Projects R eally Work (version 1.5) — Polish (http://www. projectcartoon.com /). Obrazują one w humorystyczny sposób, jak projekt jest rozu­ miany na poszczególnych etapach (cykl życia — rysunki od 1.21 do 1.24). Zachęcam do odwiedzenia tejże strony. Umożliwia ona stworzenie własnego zestawu grafik bez wnoszenia żadnych opłat.

Jak opisat to klient

Jak zrozumiat to kierownik projektu

Rysunek 1.21. How IT Projects Really Work (version 1.5) — Polish A

Jak zaprojektował to analityk

Rozdział 1. ♦ Ogólna teoria testowania

Rysunek 1.22. How IT Projects Really Work (version 1.5) — Polish B

Rysunek 1.23. How IT Projects Really Work (version 1.5) — Polish C

61

62

Testowanie oprogramowania. Podręcznik dla początkujących

Jak było to wspierane

Co reklamował marketing

Czego klient naprawdę potrzebował

Rysunek 1.24. How IT Projects Really Work (version 1.5) — Polish D

1.16. Testowanie w cyklu życia oprogramowania Cykl życia oprogramowania to okres od zmaterializowania się koncepcji jego po­ wstania do momentu, kiedy zostanie ono wycofane z użytku. W zależności od etapu, na którym znajduje się oprogramowanie, nieco inaczej podchodzi się do problematyki testowania. W najprostszym ujęciu oprogramowanie podlega następującym fazom: ♦ określenie wymagań, ♦ projektowanie, ♦ implementacja, ♦ testy, ♦ utrzymanie (pielęgnacja produkcyjna), ewolucja. Określenie wymagań polega na zebraniu i zrozumieniu oczekiwań, na podstawie których powstanie projekt opisujący już konkretne rozwiązania. Projekt stanowi pod­ stawę do wykonania implementacji i późniejszych testów funkcjonalnych. Pewną różnicę stanowi to, czy aplikacja jest pisana od podstaw, czy wnoszona zmiana jest jej ewolucją. Modyfikacje rozwojowe oprócz konieczności oceny jakości implementacji wymu­ szają często testy regresywne już istniejących obszarów aplikacji. Systemy, które nie są już rozwijane, a jedynie utrzymywane produkcyjnie, są testowane tylko w przypadku poprawek doraźnych (eliminujących błędy) oraz związanych testów regresywnych.

Rozdział 1. ♦ Ogólna teoria testowania

63

Z uwagi na brak zmian rozwojowych zaangażowanie testerów w utrzymanie takich programów jest nikłe. Największej uwagi pod względem testów wymagają projekty powołujące nowe oprogramowanie oraz projekty rozwijające jeszcze niedojrzałe sys­ temy, które podlegają nieustannemu rozwojowi. Kluczowy wpływ na jakość produkowanego oprogramowania ma obrany model jego wytwarzania. Model kaskadowy (rysunek 1.25) włącza testy w bardzo późnej fazie produkcji. Cechą charakterystyczną tego modelu jest sztywny podział procesu wy­ twórczego na bardzo hermetyczne etapy. Dopiero zakończenie jednej fazy umożliwia uruchomienie kolejnej, np. kończymy kodowanie, rozpoczynamy testy. Taka kolej rzeczy może okazać się problematyczna, gdyż faza testów, np. integracyjnych, może wykryć poważne problemy analityczne/projektowe, a zatem wymusi to ponowne za­ angażowanie projektanta, który w tym czasie zapewne będzie pracował nad kolejnym zadaniem. W praktyce oznacza to ewentualną zmianę w projekcie, modyfikację do­ kumentacji i powtórne testy. Nie jest to efektowne i optymalne rozwiązanie. Rysunek 1.25. Model kaskadowy

IMPLEMENTACJA

Model V stwarza bardzo dogodne warunki do zapewnienia wysokiej jakości dostar­ czanego produktu dzięki wczesnemu włączeniu testowania w etap wytwórczy (rysunek 1.26). Więcej na temat modelu V można znaleźć na stronie http://www.v-modell-xt.de/. Wspomniany model umożliwia wczesny udział testerów w procesie wytwórczym. Już na etapie formułowania wymagań tester ma okazję wyrazić opinię, czy proponowane rozwiązanie jest możliwe do wykonania i czy obrana droga rokuje sukces. Weryfika­ cji podlegają już pierwsze fragmenty oprogramowania (moduły), później interfejsy, tzn. integracja komponentów w całość. Następnie aplikacja testowana jest w ujęciu całościowym. Wczesne testowanie umożliwia wychwycenie np. błędów projektowych, błędów w założeniu, które w kaskadowym modelu wytwarzania oprogramowania wykryte byłyby znacznie później. Przyjmijmy, że tester przed rozpoczęciem procesu

64

Testowanie oprogramowania. Podręcznik dla początkujących

Rysunek 1.26. Model V implementacji zgłosi szereg uwag merytorycznych do projektu, których część znaj­ dzie uzasadnienie. Taki stan rzeczy przyniesie realny zysk, gdyż te same problemy (zgłoszone do projektu) zapewne byłyby podniesione już w stosunku do zmaterializowa­ nego produktu. Zatem koszty ponownego procedowania (powrót do projektu i ewentual­ na modyfikacja kodu) byłyby znacznie wyższe niż wniesienie zmian na etapie pro­ jektowania. W tym podrozdziale chciałem zasygnalizować, że nie bez znaczenia dla jakości opro­ gramowania jest to, w jakim cyklu życia jest ono wytwarzane. Z punktu widzenia testera dobrze jest rozpoznać, w jakim modelu się uczestniczy, oraz znać jego mocne i słabe strony. Jestem przekonany, że w publikacjach dotyczących bezpośrednio inżynierii oprogramowania znajdą Państwo znacznie więcej informacji na temat cyklu życia i wy­ twarzania oprogramowania. Szczególnie rekomenduję zapoznanie się w pierwszej kolejności z Manifestem Zwinnego Wytwarzania Oprogramowania (ang. Agile Manifesto, M anifesto fo r Agile Software Development). Wspomniany manifest zawiera zasady, które powinny być przestrze­ gane w metodykach zwinnego wytwarzania oprogramowania. Strona domowa A G ILE : http:// agilemanifesto.org/iso/pl/manifesto.html . Polecam zwłaszcza pogłębienie swojej wiedzy z zakresu metodyk: ♦ Programowanie ekstremalne (ang. eXtreme Programming, X P ).

♦ Scrum - iteracyjna metoda prowadzenia projektów. Więcej informacji o Scrumie można znaleźć pod tym adresem: https://www.scrum.org/scrum-guide . ♦ Kanban.

Rozdział 2.

Poziomy wykonywania testów Proces wytwarzania oprogramowania podzielony jest na fazy, w których wykonuje się specyficzne dla każdego z etapów testy. Testy dzieli się na poziomy: ♦ testy modułowe (jednostkowe), ♦ testy integracyjne wewnętrzne, ♦ testy systemowe, ♦ testy integracyjne zewnętrzne, ♦ testy akceptacyjne (odbiorcze). Rysunek 2.1 przedstawia piramidę poziomu testów. Testy wykonywane są zgodnie z oddolną interpretacją infografiki, tj. od testów modułowych aż po testy akceptacyjne. Rysunek 2.1. Piramida poziomu testów

66

Testowanie oprogramowania. Podręcznik dla początkujących

2.1. Testy modułowe Testy modułowe wykonuje się na etapie wytwarzania kodu. Uczestnikami tego ro­ dzaju testów są najczęściej programiści, którzy w fazie implementacji poddają weryfika­ cji własny kod. Wspomniane testy muszą odnosić się do niewielkich i ściśle wyizolowa­ nych fragmentów kodu. Polegają one na wykonywaniu wybranego fragmentu instrukcji w celu zweryfikowania, czy realizuje ona swoją funkcję zgodnie z założeniami. Pro­ gramista przygotował metodę, która konwertuje numer NRB (Numer Rachunku Ban­ kowego) na IBAN (ang. International Bank Account Number — pol. Międzynarodowy Num er Rachunku Bankowego ). Wspomniana metoda będzie wielokrotnie używana w różnych miejscach systemu. Test modułowy polegać będzie na wywoływaniu owej metody z podaniem jako parametru wejściowego numeru NRB i weryfikacji otrzyma­ nego wyniku. Wywołanie metody może odbywać się z poziomu środowiska deweloper­ skiego bez zastosowania GUI. Na tym koniec. Testy modułowe powinny odnosić się do małych podmiotów, a ich wynik powinien być zależny od innych elementów, które potencjalnie mają znaleźć się w gotowej aplikacji. Testy modułowe nie powinny wnikać w szczegóły procesu biznesowego. Analizie i ocenie podlega jedynie mały i wyizolowany fragment kodu. W przypadku kiedy nabierzemy zaufania do testowanych fragmentów kodu, możemy rozpocząć składanie ich do postaci gotowego produktu lub większego komponentu. Testy modułowe wykonuje się zwykle w środowisku deweloperskim z dostępem do kodu źródłowego. Wymaga to od testera — o ile nie jest programistą — umiejętności czytania i wykonywania kodu oraz pisania własnych skryptów (fragmentów kodu). Bywa, że przetestowanie pewnego modułu wymaga zaangażowania elementów pobocznych, np. symulatora usługi sieciowej. Dlaczego należy wykonywać testy modułowe? Błędy wykryte we wczesnej fazie produkcji oprogramowania kosztują znacznie mniej niż poprawa oraz usuwanie ich skutków w kolejnych fazach wytwarzania lub użyt­ kowania produkcyjnego aplikacji. Wykryte problemy usuwane są natychmiast, przez co minimalizuje się ryzyko propagacji negatywnego wpływu wadliwego kodu na po­ zostałe moduły np. poprzez odziedziczenie wady. Błędy wykryte w tej fazie zwykle nie znajdują odzwierciedlenia w postaci formalnego zgłoszenia, co przyspiesza udosko­ nalanie kodu i nie niesie ze sobą ryzyka krytycznych uwag osób trzecich. Jest to bar­ dzo bezpieczna i efektywna forma testów własnego kodu. Kompilator nie weryfikuje in­ tencji programisty. Zatem pomimo że kod został skompilowany, nie można go uznać za poprawny bez przeprowadzenia testu jednostkowego. Odłożenie procesu testowania do momentu złożenia w całość wszystkich elementów niesie ze sobą znaczne ryzyko, że nie uda się uruchomić aplikacji lub pewnych funkcjonalności za pierwszym razem. Błędy, które zostaną ujawnione, mogą mieć przyczynę głęboko ukrytą w kodzie. Prze­ szukiwanie „rozdmuchanych” źródeł w celu wyizolowania przyczyny problemu będzie czasochłonne i zapewne irytujące. Testy modułowe pozwalają na wyeliminowanie ty­ powych problemów w podstawowej ścieżce obsługi systemu. Im mniej problemów zostanie przeniesionych z fazy implementacji do fazy formalnych testów, tym szybciej gotowy produkt zostanie przekazany do odbiorcy, a jego jakość wzrośnie.

Rozdział 2. ♦ Poziomy wykonywania testów

67

2.2. Testy integracyjne U podstaw testów integracyjnych leży opieranie jednego procesu biznesowego na wielu różnych systemach, podsystemach i aplikacjach. Heterogeniczność ostatecznie oferowa­ nego użytkownikowi końcowemu rozwiązania wymusza przeprowadzenie pełnego testu biznesu w oparciu o scalone środowisko. Aby było to możliwe, uprzednio należy zwery­ fikować interakcję pomiędzy poszczególnymi modułami. Zakończenie tych prac z ocze­ kiwanym skutkiem stanowi podstawę do traktowania wszystkich modułów jako jeden system. Niezachwiane przekonanie o spójności systemu otwiera drogę do pełnych testów funkcjonalnych w całościowym ujęciu obsługi biznesu. Testy integracyjne to szczególny rodzaj działań podejmowanych w celu zbadania ko­ operacji oraz wzajemnego oddziaływania dwóch lub więcej modułów systemu. Przez desygnat „moduł” należy rozumieć zupełnie autonomiczny produkt lub fragment kodu, który ostatecznie jest ściśle spojony z główną architekturą systemu. Testy integracyjne mają wykazać: ♦ czy moduły poprawnie współpracują, tj. czy nie wystąpiły przeszkody natury technologicznej oraz czy wzajemnie świadczone usługi spełniają oczekiwania (logika); ♦ jak zachowują się poszczególne elementy w sytuacji awarii, błędów lub niestabilnej pracy w przypadku dysfunkcji jednego z nich (wzajemne oddziaływanie); ♦ czy kojarzone wzajemnie elementy realizują założony proces biznesowy (logika biznesu); ♦ czy infrastruktura techniczna zapewnia optymalne warunki pracy dla skomplikowanego systemu (wielomodułowego); ♦ czy nie ma luk w logice biznesu, tj. czy nie ujawniły się problemy i/lub potrzeby, które nie zostały przewidziane na etapie projektowania rozwiązania. Prace integracyjne rozpoczynają się już w momencie łączenia kodu dwóch lub więcej modułów tej samej aplikacji (integracja wewnętrzna). Komponenty te mogą być przy­ gotowane przez zupełnie niezależnych programistów, a finalnie podlegają integracji. Wymienione elementy mogą w mniejszym lub większym stopniu ulegać integracji. Rolą testera jest zweryfikowanie relacji pomiędzy nimi. Zdarza się, że programista jest przekonany, iż integrowane elementy mają śladowy wpływ na pracę pozostałych frag­ mentów kodu. Niemniej jednak w ujęciu całościowym błąd w jednym z nich poważnie rzutuje na pracę całego systemu. Iluzoryczne przekonanie o nikłej zależności lub wręcz przezroczystości kodu integrowanego z dotychczasowymi funkcjonalnościami aplika­ cji bywa zgubne w skutkach. Omawiane prace należy podejmować jak najbliżej kodu, tj. na etapie prac programistycznych i testów wewnętrznych. Rysunek 2.2 przedstawia szkolny schemat blokowy modułów jednej aplikacji. Programista X przygotował blok B. Chcąc wykonać jego testy, musi zintegrować go z blokiem A lub zasymulować jego działanie. Programista Y wykonał blok A, który z założenia ma pracować z blokami B i C. Modułowe testy integracyjne polegają na łączeniu ze sobą fragmentów kodu, które

68

Testowanie oprogramowania. Podręcznik dla początkujących

Rysunek 2.2. Schemat wzajemnego oddziaływania bloków jednej aplikacji

wchodzą w bezpośrednią interakcję. Programista lub tester uruchomi blok A i sprawdzi, czy to, co „wysyła” do elementu C, jest poprawne. Integrując bloki A, B i C, weryfi­ kujemy ich wzajemną kooperację, mimo że nie realizują one pełnej funkcjonalności z punktu widzenia użytkownika końcowego. Kolejnym momentem w procesie produkcji oprogramowania, w którym wykonywane są testy integracyjne, jest zestawianie odrębnych modułów na etapie weryfikacji funkcjo­ nalnej. Jest to arcyciekawa sytuacja z uwagi na to, że kod odpowiadający za odrębne fazy obsługi biznesu może być zrealizowany przez zupełnie niezależne podmioty. Zwykle jako podstawa do przygotowania „wtyczki” dla obcego systemu musi wystar­ czyć dokumentacja dostarczona przez potencjalnego integratora, tj. klienta, który bę­ dzie „spinał wszystko w całość”. Nadmieniony materiał może zawierać definicję pli­ ków wymiany danych (np. TXT, XML, CSV itp.), opis usługi sieciowej, np. WSDL, schemat udostępnionych obiektów na bazie danych w postaci perspektyw, przykłady wywołania upublicznionych procedur etc. Niezależnie od wybranego rozwiązania do­ stęp do niego bywa znacznie utrudniony lub wręcz niemożliwy. Oczywiście taka sy­ tuacja już na etapie kodowania może być źródłem problemów, lecz prawdziwe trud­ ności ujawniają się dopiero w momencie testów jakościowych. Rozważmy hipotetyczną sytuację w oparciu o rysunek 2.3. Pełny proces biznesowy wymaga zaangażowania trzech aplikacji. Testy integracyjne będą odbywały się na styku produktu C i B oraz B i A. Biznes (funkcjonalność) natomiast będzie weryfikowany przy użyciu wszystkich bloków A, B oraz C. Aplikacja C stanowi graficzny interfejs użytkownika, posiadający nikłą logikę biznesową, a zarazem bardzo rozbudowane możliwości prezentacji i obsługi danych. Główny mechanizm realizacji zadanego biznesu spoczywa na programie B. Niemniej jednak mogą wystąpić sytuacje, w których podsys­ tem B będzie musiał posiłkować się wsparciem programu A. Reasumując, w realizację logiki mogą być zaangażowane bloki B oraz A. Natomiast aplikacja C jest inicjatorem przetwarzania, a zarazem konsumentem wyniku, tj. prezentacji rezultatu. Systemy o złożonej architekturze najczęściej poddawane są realnej próbie dopiero w środowi­ sku testowym zamawiającego. Odbiorca oprogramowania ma przewagę nad wykonaw­ cami poszczególnych komponentów w postaci nieskrępowanego dostępu do wszyst­ kich elementów. Drugą kwestią jest posługiwanie się danymi bardzo zbliżonymi do rzeczywistych np. poprzez włączenie w proces testowania kopii bazy z produkcji. Po­ wyższe zabiegi urealniają testy funkcjonalne (pełnego biznesu) poprzez posługiwanie się niemalże faktycznymi danymi zgromadzonymi w dużym wolumenie. Obsługa pełnego

Rozdział 2. ♦ Poziomy wykonywania testów

69

Rysunek 2.3. Schemat interakcji trzech niezależnych aplikacji

procesu biznesowego w fazie prac integracyjnych lub ostatecznych testów odbiorczych może ujawnić luki w opracowanej koncepcji. Zdarza się, że w wyniku testów zidenty­ fikowane są problemy, które nie były przewidziane w projekcie. Problemy te mogą przełożyć się na zmianę rozwiązania. Dokładniej rzecz ujmując: na jego dopracowanie, na przykład poprzez dopisanie drobnych funkcjonalności, modyfikację założeń wstępnych etc. Testy integracyjne stanowią pierwszy etap weryfikacji, czy przyjęte rozwiązanie oraz jego implementacja zaspakajają potrzeby biznesowe (w całościowym ujęciu procesu). Pierwszym, a zarazem najmniej kłopotliwym scenariuszem jest integrowanie modułów (całych programów), które wykonane są przez jednego producenta. W teorii wskaza­ ne testy powinny być wykonane bez większych problemów, a ewentualne przeszkody w postaci błędów w implementacji lub niejasności w dokumentacji rozwiązane wewnątrz organizacji. Praktyka dowodzi, że niestety również ten scenariusz naznaczony jest pewnymi zakłóceniami w trakcie realizacji projektu testowego. Wynika to głównie z organizacji pracy oraz nie do końca jasnej i zdrowej rywalizacji pomiędzy zespołami wewnątrz korporacji. Wskazałem korporację, gdyż pojęcie klienta zewnętrznego oraz wewnętrznego jest szeroko stosowane w dużych przedsiębiorstwach. Pojęcie samo w so­ bie nie kryje niczego złego, choć zauważalne są problemy w relacjach pomiędzy ze­ społami wynikające z zawiłej, a bywa, że i naciąganej interpretacji tego terminu. Ide­ alizując, można przyjąć, że funkcjonujące procedury formalne w pełni zabezpieczają potrzebę kooperacji różnych zespołów w celu osiągnięcia ostatecznego rezultatu. Nieco mniej przyjemną sytuacją jest nieposiadanie jednego lub więcej komponentów „na własność”, kiedy są one udostępnione grzecznościowo przez klienta. Jest to sto­ sunkowo dobre rozwiązanie, chociaż uzależnione od dobrej woli współpracy. Pewną trudnością dla procesu integracji mogą być ewentualne niedociągnięcia w kodzie po drugiej stronie, ale właśnie po to się wykonuje testy integracji, aby te problemy wy­

70

Testowanie oprogramowania. Podręcznik dla początkujących

eliminować. Generalnie „my” czy partner po przeciwnej stronie musimy czekać na ewentualne modyfikacje kodu w celu kontynuowania procesu integracji. Niemniej jednak jest to dobra droga. Wymaga ona zaangażowania zasobów klienta jako pośred­ nika, lecz uzyskujemy wartość dodaną w postaci wczesnego rozminowania pola. Bujna wyobraźnia podpowiada, co może się stać, jeżeli podejmiemy próbę zintegrowania dwóch programów bez wcześniejszego „docierania” ich razem. Najtrudniejszą sytuacją jest konieczność wyprodukowania modułu klienckiego do obce­ go systemu bez dostępu do tego zasobu. Większość trudności ujawni się w momencie uruchamiania kodu i testów funkcjonalnych. Dużo zależy od roli, jaką dla testowanej funkcjonalności odgrywa zewnętrzny system. Bywa, że brak dostępu do drugiego programu w minimalnym stopniu ograniczy testy. Bywa również, że zupełnie je unie­ możliwi. Załóżmy, że testowana funkcjonalność realizuje jakiś biznes zdefiniowany w 10 logicznych krokach, gdzie kroki 2., 5. oraz 8. wymagają połączenia z usługą sie­ ciową w celu pobrania/przeliczenia jakichś danych. W takich okolicznościach przete­ stujemy tylko krok nr 1. Drugi już wymaga interakcji z web service (WS). W tym momencie wyklarowała się potrzeba zaślepienia wywoływanej metody WS przez naszą aplikację, tak aby mogła ona przejść do kroku nr 3 itd. Trzeba wyprodukować symu­ lator systemu zewnętrznego. Temat zaślepiania żądań do zewnętrznych aplikacji będzie omówiony szerzej w dalszej części książki. Do typowych problemów (błędów) wykrywanych w procesie integracji należy zaliczyć: ♦ Niespójność wysyłanego schematu XML z oczekiwaniami klienta lub serwera np. w wyniku przygotowania klienta WS w oparciu o nieaktualny opis usługi (WSDL) lub błąd w kodzie. ♦ Treść danych przekazywana w pliku wymiany danych zawiera znaki specjalne, na które negatywnie reaguje druga aplikacja. Przykładowa nazwa jakiejś organizacji, fundacji może zawierać cudzysłów, który eksportowany jest do treści pola. Dokumentacja opisująca pliki wymiany może nie opisywać szczegółów lub wyjątków. ♦ Zderzenie dwóch technologii lub nawet różnych wersji tych samych serwerów może powodować problemy natury integracyjnej. ♦ Bywają sytuacje, że w jakichś okolicznościach jedna ze stron będzie przekraczała czas odpowiedzi na żądanie (ang. time out ). ♦ Wyobrazić można sobie sytuację, że obrót danymi odbywa się za pomocą pliku wymiany danych, w którym koniec linii ustalony jest na znak LF, a w wyniku pośredniego działania jakiegoś programiku, który kopiuje plik z miejsca A do B, zajdzie niejawna konwersja znaku końca linii na CRLF. Próba odczytania takiego zbioru zakończy się niepowodzeniem. Czy taki scenariusz można przewidzieć w testach funkcjonalnych? W praktyce jedna aplikacja wygeneruje poprawnie LF, a druga poprawnie odrzuci znak CRLF. Gdzie jest błąd?! Może w jakimś „starym” programiku, którego nie braliśmy pod uwagę na etapie testów? ♦ Testy integracyjne stanowią dobrą okazję do masowego wczytywania plików, wymiany danych przez funkcje WS itp. Zdarza się, że błędy, np. przepełnienie bufora, przekroczenie zakresu zmiennej itp., ujawniają się dopiero przy „ogromnej” ilości danych.

Rozdział 2. ♦ Poziomy wykonywania testów

71

♦ Integracja systemu ujawnia wszelkie różnice w rozumieniu funkcji, jakie ma pełnić każdy z elementów, w tym po której stronie maj ą być obsługiwane określone wyjątki. ♦ Luki w opracowanej koncepcji rozwiązania, na podstawie której była wykonana implementacja. ♦ Wiele innych problemów...

2.3. Testy systemowe Przedmiotem testów systemowych jest cała aplikacja lub jej samodzielny fragment, który znajduje odwzorowanie w projekcie, tj. wchodzi w zakres projektu. Najodpo­ wiedniejszą formą testów funkcjonalnych jest zastosowanie techniki czarnoskrzynkowej. Niemniej jednak technika białej skrzynki z powodzeniem może być wykorzystywa­ na jako uzupełnienie głównego wątku testów. Kluczem do sukcesu jest prowadzenie testów w środowisku testowym jak najbardziej zbliżonym do produkcyjnych warun­ ków funkcjonowania aplikacji. Weryfikacja aplikacji w warunkach możliwie wiernie odwzorowujących docelowe środowisko pracy zmniejsza ryzyko przeoczenia błędów i problemów, które mogą wynikać z różnic w specyfice obu środowisk. Więcej infor­ macji na temat środowiska testów znajduje się w rozdziale poświęconym owej tema­ tyce w niniejszej książce. Równie istotne jest to, kto wykonuje testy systemowe. Najlepiej byłoby, aby czynił to niezależny zespół testerów, tzn. taki, który zachowuje dużą autonomiczność wobec zespołu programistycznego w aspekcie środowiska testów oraz zasobów ludzkich. Testy systemowe (ang. system testing) powinny ujmować wymagania zarówno nie­ funkcjonalne, jak i funkcjonalne. Jest to faza, w której ocenia się globalnie produkt bez nadmiernego nacisku na zgłębianie wewnętrznej architektury i instrukcji kodu aplikacji. Testy systemowe odnoszą się do aplikacji w ujęciu całościowym. Oznacza to, że zo­ bowiązani jesteśmy do weryfikacji wszystkich funkcji wraz z analizą korelacji po­ między nimi. Załóżmy, że otrzymaliśmy do testów aplikację lub nowy moduł, który administruje fakturami VAT. Testy systemowe wymagają zweryfikowania wszystkich ścieżek obsługi owego dokumentu, m.in. wystawienia FV, korekty, wydruku, filtro­ wania, generowania do pliku PDF, akceptacji etc. Tego rodzaju testy mogą ujawnić potrzebę zastosowania zaślepek lub symulatorów zewnętrznych systemów, z którymi nasza aplikacja będzie wchodzić we współzależ­ ność lub w których będzie występować jedynie jako klient. Specyfika i zakres testów systemowych stawiają ten rodzaj weryfikacji w roli bardzo dobrego kandydata do automatyzacji czynności (testów). Testy systemowe to: ♦ testy funkcjonalne, ♦ testy wydajnościowe,

72

Testowanie oprogramowania. Podręcznik dla początkujących

♦ testy regresywne, ♦ testy ergonomii, ♦ testy instalacji, ♦ testy bezpieczeństwa.

2.4. Testy akceptacyjne Testy odbiorcze wykonywane są bezpośrednio przez zamawiającego w oparciu o własne zasoby lub poprzez zlecenie prac niezależnemu zespołowi testerskiemu. Testy te mają potwierdzić zgodność weryfikowanego produktu z zapisami w umowie i obowiązują­ cymi przepisami prawa. Celem testów akceptacyjnych jest weryfikacja i potwierdzenie, czy wszystkie zapisy w kontrakcie zostały zrealizowane w sposób zaspokajający ocze­ kiwania. Pozytywne zamknięcie fazy testów odbiorczych stanowi podstawę do finan­ sowego rozliczenia kontraktu. Testy akceptacyjne powinny odnosić się do formalnie spisanych kryteriów odbioru oprogramowania. Wspomniane kryteria zwykle uzgad­ niane są na etapie negocjacji kontraktu. Opisywana tu sytuacja odnosi się do opro­ gramowania pisanego na zamówienie. Nieco inaczej wygląda sytuacja w przypadku aplikacji „pudełkowych”. Oprogramowanie z półki może być poddane dwóm typom testów akceptacyjnych: alfa i beta. Testy alfa są wykonywane wewnątrz organizacji, która wyprodukowała oprogramowanie, choć we­ ryfikacji dokonuje niezależny zespół, tj. zespół, który nie brał udziału w procesie wytwarzania. Testy beta realizowane są poza organizacją wykonującą kod przez grupę użytkowników docelowych. Firmy produkujące oprogramowanie pudełkowe są żywo zainteresowane uzyskaniem informacji zwrotnej (potwierdzeniem) o wysokiej jako­ ści własnego produktu przed oficjalnym wprowadzeniem go na rynek. Niezależnie od typu oprogramowania (pudełkowe, na zamówienie) powinno ono rów­ nież być poddane testom akceptacyjnym w aspekcie obowiązujących przepisów prawa.

Rozdział 3.

Typy testów Testy dzieli się według przyczyny ich wykonywania. W celu zweryfikowania pozio­ mu bezpieczeństwa lub wydajności realizuje się testy niefunkcjonalne. Ocenę funkcji opiera się na testach funkcjonalnych. W sytuacji kiedy chcemy potwierdzić, że wpro­ wadzona modyfikacja nie wpłynęła negatywnie na pozostałe obszary systemu, wykonuje się testy regresywne. W tym rozdziale przedstawię podział testów według celu ich wykonywania. Dodat­ kowo dla testów niefunkcjonalnych zrealizujemy kilka przykładów praktycznych.

3.1. Testy funkcjonalne Testy funkcjonalne, jak sama nazwa wskazuje, odnoszą się bezpośrednio do funkcji, jakie realizuje system lub jego moduł. Podstawą dla tego typu prac jest specyfikacja funkcjonalna, której zapisy mówią o możliwościach, cechach i właściwościach sys­ temu. Niestety może ona (dokumentacja) nie odnosić się w pełni do ostatecznej im­ plementacji, tj. pewne funkcje i zachowania mogą być nieudokumentowane. Wspomnia­ ny stan rzeczy może wynikać z kilku powodów: ♦ z jakichś przyczyn nie zadbaliśmy o pełną i aktualną dokumentację; ♦ dokumentacja jest mało precyzyjna i niskiej wartości merytorycznej; ♦ w fazie implementacji i wstępnych testów ujawniła się konieczność rozbudowy, poszerzenia zakresu prac o aspekty, które nie zostały jeszcze ujęte w projekcie (brak aktualizacji); ♦ pewne cechy i właściwości systemu mogą być wykonywane poprzez analogię do poprzednich funkcji lub na bazie „zwyczajowości”. Zważywszy na powyższe zagrożenie, tester musi umieć radzić sobie w sytuacji niedo­ stępności pełnej i szczegółowej dokumentacji. Istotą testów funkcjonalnych jest zro­ zumienie wymagań, jakie ma spełniać finalny produkt.

74

Testowanie oprogramowania. Podręcznik dla początkujących

Testy funkcjonalne odpowiadają na pytanie: co robi system (umożliwia doładowanie karty telefonu, wyświetla historię operacji, generuje potwierdzenie przelewu etc.), w od­ różnieniu do testów niefunkcjonalnych, które poszukują odpowiedzi na pytanie: jak działa system (jak szybko przygotuje billing dla 50 000 połączeń, jak obsłuży 20 000 użytkowników jednocześnie itp.). Przyjmijmy, że serwis ogłoszeń internetowych ma zostać rozbudowany o filtr uła­ twiający przeszukiwanie pozycji. Filtr ma umożliwiać wybieranie danych według na­ stępujących kryteriów: ♦ województwo, z którego pochodzi ogłoszenie; ♦ data zamieszczenia; ♦ rodzaj ogłoszenia (sprzedaż/kupno). Wykonując testy funkcjonalne, szukamy potwierdzenia, czy system robi to, czego od niego oczekujemy (odpowiedź „co robi”, czy umożliwia przeszukiwanie zasobów w e­ dług założenia). Natomiast testy niefunkcjonalne będą polegać na sprawdzeniu dzia­ łania filtra przy dużym zakresie danych np. 300 000 ogłoszeń. Sprawdzać będziemy, „jak” zachowuje się opcja przeszukiwania dla dużego wolumenu danych. Markerem może być czas odpowiedzi dla pojedynczego zapytania. Możemy również poddać pró­ bie mechanizm dla 50 równolegle wysyłanych żądań przeszukania danych.

3.2. Testy niefunkcjonalne Testy niefunkcjonalne (ang. non-functional), jak sama nazwa wskazuje, nie odnoszą się bezpośrednio do funkcjonalności produktu. Tego rodzaju testy mają na celu ustalenie charakterystyki oprogramowania, tj. zachowania systemu w określonych okoliczno­ ściach. W skład podstawowych testów właściwości systemu wchodzą: ♦ testy wydajnościowe, obciążeniowe i przeciążeniowe; ♦ testy bezpieczeństwa; ♦ testy ergonomii; ♦ testy przenośności kodu (instalacji).

3.2.1. Testy wydajności Badanie wydajności systemu ma dać odpowiedź, jak system zachowuje się przy okre­ ślonym obciążeniu. Tego rodzaju testy należą do grupy niefunkcjonalnych i są szcze­ gólne w całościowym ujęciu terminu testowania oprogramowania. Wyniki pomiaru systemu służą do zbudowania charakterystyki oprogramowania, np. zależności pomiędzy zachowaniem systemu a jednoczesną liczbą użytkowników. Uzyskany wykres przed­ stawiający te relacje powinien być porównany z oczekiwanym (założonym) rezultatem.

Rozdział 3. ♦ Typy testów

75

Przez takie porównanie uzyskamy informację, czy system spełnia oczekiwania. W grupie wspomnianych oczekiwań należy wymienić weryfikację, czy: ♦ system działa stabilnie dla założonej maksymalnej grupy użytkowników; ♦ czasy odpowiedzi są na akceptowalnym poziomie dla normalnego trybu pracy, a tym bardziej nie przekraczają przewidzianego limitu czasu dla operacji (ang. time-out); ♦ logika biznesowa spełnia swoją rolę;

♦ system „nie gubi” danych przy dużych obciążeniach; ♦ w razie przeciążenia system uruchomi procedury awaryjne. Uzyskanie informacji o rzeczywistych parametrach wydajnościowych systemu otwiera drogę do konstruktywnego planowania dalszego rozwoju oprogramowania. W przypad­ ku kiedy wyniki będą niezadowalające, zainicjowana zostanie procedura naprawcza. Niedopuszczalne są zaniedbania polegające na zaniechaniu testów wydajnościowych. Podmiot odpowiedzialny (najczęściej właściciel) powinien znać możliwości systemu, jego słabe i mocne strony i mieć przygotowane scenariusze na wypadek ewentualnych problemów. Pewnym novum dla testerów może okazać się fakt, że istnieje prawdopo­ dobieństwo ujawnienia się błędów w logice przy dużym obciążeniu, pomimo iż prze­ widziane testy funkcjonalne zakończyły się sukcesem. Wyróżnia się trzy podstawowe typy testów: ♦ testy wydajnościowe (ang. performance testing), ♦ testy obciążeniowe (ang. load testing), ♦ testy przeciążeniowe (ang. stress testing).

Testy obciążeniowe polegają na symulacji obciążenia systemu dużą — zbliżoną do maksymalnej — liczbą użytkowników przez zadany zakres czasu (utrzymywanie ob­ ciążenia) przy realizacji wybranego scenariusza testów, np. realizowania transakcji. Wymuszenie, aby system funkcjonował na pograniczu założonej maksymalnej liczby sesji, służy do zmierzenia czasu odpowiedzi na pojedyncze żądanie. Oprócz liczby jednoczesnych użytkowników dla testów obciążeniowych istotne jest, jakie obszary systemu analizujemy. Inaczej będzie reagował system dla 1000 sesji, w których jedy­ nie pobieramy treść statyczną, a inaczej, kiedy tyleż samo klientów będzie realizo­ wało poprzez aplikację internetową transakcje na bazie danych lub wykonywało import dużej ilości danych. Planując testy, należy opracować scenariusze tak, aby obowiąz­ kowo zweryfikowały najbardziej newralgiczne miejsca aplikacji. Testy obciążeniowe mają za zadanie potwierdzić, czy system sprosta stawianym mu wymogom pod wzglę­ dem wydajności. Testy przeciążeniowe wykonuje się w celu zbadania, jak aplikacja zachowuje się w momencie przekroczenia jej dopuszczanego obciążenia. Taka sytuacja może się zda­ rzyć, zatem kluczowa dla podmiotu jest informacja, jak system reaguje na takie zda­ rzenie. W przypadku przeciążenia system powinien pracować w trybie awaryjnym, tj. w taki sposób, jak to zostało założone. Przeciążenia systemu można dokonać poprzez zbyt dużą liczbę użytkowników, hurtową ilość danych (np. masowe zasilenia z plików) i/lub ograniczenie (konsumpcję) zasobów systemowych.

76

Testowanie oprogramowania. Podręcznik dla początkujących

Celem testów przeciążeniowych jest ustalenie: ♦ czy aplikacja zareagowała zgodnie z założeniami; ♦ czy przeciążenie systemu nie wpływa na bezpieczeństwo; ♦ czy poprawnie działa procedura powrotu do normalnego trybu pracy; ♦ czy nie nastąpiła utrata danych lub ich spójności w wyniku przejścia w stan awaryjny; ♦ czy w wyniku przeciążenia nie ujawniły się dodatkowe błędy. Testy wydajnościowe mają potwierdzić, że system zachowa się poprawnie w sytuacji niskiego i znacznego obciążenia przez użytkowników. Kluczowe funkcje aplikacji po­ winny być wykonywane w akceptowalnym czasie. Tego typu testy mają dać odpo­ wiedź, jak wzrost liczby jednocześnie obsługiwanych użytkowników wpływa na czas przetwarzania żądania. W odróżnieniu od testów obciążeniowych nie jest wymagane długotrwałe utrzymywanie wysokiego obciążenia systemu. Istotą testów wydajno­ ściowych jest zbadanie czasu odpowiedzi (przetwarzania) dla poszczególnych funkcji w różnych okolicznościach (przy akceptowalnym obciążeniu). Często zdarza się, że większość funkcji serwisu działa sprawnie, z wyjątkiem jednego lub dwóch miejsc, gdzie następuje tzw. przytkanie, czyli wąskie gardło. Namierzenie tego miejsca pozwoli na eliminację potencjalnego zagrożenia i wzrost wydajności całej aplikacji. Przeprowadzenie testów wydajnościowych wymaga od testera dużego doświadczenia, znajomości systemu, a czasami kunsztu w tej materii. Tego rodzaju prace są specyficzne, a zebrane podczas nich doświadczenie stanowi cenne know-how testera. W celu prak­ tycznego wprowadzenia do testów posłużymy się narzędziem Apache JMeter. JMeter to program napisany w języku Java, który umożliwia symulowanie obciążenia aplikacji internetowej lub API (ang. Application Programming Interface) oraz mie­ rzenie ich wydajności. Narzędzie można pobrać ze strony domowej projektu: http:// jmeter.apache.org/. Do najważniejszych opcji programu należy zaliczyć możliwość testowania: ♦ baz danych przez JDBC Driver; ♦ SOAP, HTTP i HTTPS; ♦ SMTP, POP3 oraz IMAP. Szczegółowa instrukcja wraz z wymaganiami instalacji dostępna jest na stronie interne­ towej dostawcy programu. Po uruchomieniu narzędzia dostępny jest GUI (rysunek 3.1). Testowanie bazy danych Zdarza się, że w projekcie technicznym przy opisie perspektywy lub tabeli projektant zastrzega, że wszelkie przeszukiwanie musi być wykonywane obligatoryjnie z klau­ zurą WHERE. Ma to bezpośredni związek z wydajnością oraz liczbą danych, jaka jest przechowywana/prezentowana w wymienionych obiektach. Zatem tester powinien się pokusić o sprawdzenie, jak będzie reagowała baza danych przy masowym wykony­ waniu zaprojektowanej instrukcji SQL. W celu poznania narzędzia JMeter posłużymy się trzema przykładami. Pierwszy z instrukcją INSERT INTO, drugi z warunkiem WHERE, a trzeci z wywołaniem procedury składowanej w bazie danych.

Rozdział 3. ♦ Typy testów

77

Rysunek 3.1. Apache JMeter 2.9 — GUI Apache JMeter napisany jest w Javie, a zatem w celu połączenia się z bazą danych należy użyć biblioteki sterowników JDBC. Odpowiednia biblioteka JAR musi zostać skopiowana do katalogu JMETER_HOME/lib lub JMETER_HOME/lib/ext. Sterownik JDBC musi być odpowiedni dla bazy danych, z którą chcemy nawiązać połączenie. W przypadku braku sterownika lub innych problemów z importem plików class JMeter odnotuje błąd w logu (rysunek 3.2). » PlanTeitowTDoofcMyCCUmx »pache-jrieter-2^.apache-jmeter-ZiW»ri.PlanTeitc-oTDoofcfctySQtjn* -¿pacheJM«ef[Z9r14379611

HW - hm SrjrrJi Kim oprano?. Hnp j "U W « I □ + - + t * ? ¿ HWiilKtun_lBuuO«;SUI. POCii«n«o«t 1W W 0 t { ümwettHttuwJíySUL Uhl rh'.m u|ihalriral (lin y VXWI AutoCummit T i k rruttoantft TraiDocflonisołotlonr DCTAULT

h

4 M * '

05

Ki E t

▼ —

Keepjurve-Tw U.1I 1IMMITIIMMyl(n K f i IM HI VaiddiuaOwnr Celni 1

-

Dotaba)«URUJi rumunmcwisourca) ar.».»n»iuRLCiaiSLoa3*r)i rumunKncnn3ourca) •tjMtecurUiAcc«isControlleracTrMlegeóiNatrtuetnoa: at,».anetuRLCiaääLoaaertriuciassuniaiannSource) a(laiaJanq-Claaabuetlet.luaiiClaaadJiibiuMiiiSuuite) ;i ttr.i baiqfJ.r.:J K u b IcŁiiIfJ.r.i^l hikiximi f i i u n ) :ś pr.itag( X rii; kB KanrU(H;a(icMraiixl) arja. a lang (üass nvf ia*na(i mmmin Hnara) atorgacacMavatorvarcaasurcatasourcoKasourceUmiangJOt>cUata3ourc*ccnligur»(K«iourc«łJmiangjo&cüataüourc*. atorg.acacn«jmatar.proCoco u s e t b o o k ; D atabase changed m y s q l> d e s c t b _ j m e t e r ; l

Field

! ! ! !

id_jn ! int inie ! uarchar nazwisko ! v arc h a r d 0 0 ) timestamp ! tinestamp

i Type

4 ro w s i n s e t

Nuli

! Key

Def ault

Extra

NO NO NO NO

! PRI

NULL NULL NULL CURRENT_TIMES T AMP

auto increment ! i !

\

1

i

s e l e c t c o u n t < * > f r o n t b _ j n e t e r ; ! co u n tO >

!

+



!

0 --- :

+-------------+ 1 ro w i n s e t

Farmularz doładowań telefonu - Potwierdzenie < /h e a d ł-

< tr>

Dane poprawne? 4itle> Formularz doladow ań telefonu - PotwierdzeniecAitles

cforrt size="3" color= "black" face="/Vial"> Potwierdź doładow anie telefonu c /h 1> c h 2 i Niestety wystąpił problem z serwerem
Skontaktuj się z BOK pod n r 0-700-700-700

Kwota doładowania: 200 PLN




Kwota doładow ania: < /td>

500 PLNc4d>

< A a b\e > < b r>

cb^Dane poprawne? < /b> cinput type="subm it" vaLe="A K C E P TU J" /> c/form >

c/body> 11:94

411/1202

F in d ... (p re s s C tr l+ E n te r to h ig h lig h t a ll)

Rysunek 3.68. Fiddler — modyfikacja kodu wysyłanego do przeglądarki, dodanie własnych tagów HTML Rysunek 3.69. Strona wyświetlająca detale operacji „wzbogacona” o obcą treść

i_] Formulara doladowańtelefonu - Potwrer,,. | + localhost:8080.'TestBook,TestSep/letido?nrRach=102Q30405Q00Q09&nrTelefonu=lQ0-20Q-300&kwotaDoladowania=500

P o tw ierd ź d o ład o w an ie telefon u Niestety wystąpił problem z serwerem. Skontaktuj się z BOK pod nr. 0-700-700-700 Rachunek obciążany:

102030405000009

Nr telefonu:

100-200-300

Kwota doładowania:

500 P IN

Dane poprawne? |

a k c e p tu j

Oparcie ograniczenia dostępu do funkcji systemu na znaczniku disabled języka HTML może przysporzyć pewne trudności w realizacji zamierzonego celu (listing 3.14, rysunek 3.70). Takie „zabezpieczenie” można obejść, posługując się analogiczną metodą, jakiej użyliśmy przy modyfikacji treści. W przechwyconym komunikacie od­ powiedzi należy usunąć atrybut disabled. Przykład takiego zabiegu prezentuje listing 3.15, gdzie za pomocą narzędzia Fiddler usunięto znacznik disabled. Rysunek 3.71 prezentuje efekt działania zmodyfikowanego kodu w przechwyconej sesji — przycisk oraz pola są dostępne dla użytkownika. Warto rozważyć zasadność wysyłania obiektu akcji (przycisk) oflagowanego jako niedostępny. Nieaktywny przycisk można zastą­ pić komunikatem, który równie jednoznacznie poinformuje użytkownika o braku do­ stępności do opcji i jednocześnie nie stanowi potencjalnego celu ataku.

116

Testowanie oprogramowania. Podręcznik dla początkujących

Listing 3.13. Źródło zmodyfikowanej strony z poziomu przeglądarki



< t i t l e > F o r m u l a r z doładowań t e l e f o n u - P o t w i e r d z e n i e < / t i t l e >

Potwierdź doładowanie t el ef onu N i e s t e t y wy s t ą p i ł problem z serwerem.
Sko nt a kt uj s i ę z BOK ^ p o d n r . 0- 700-700-700 f o r m a c t i on =" / Te s t Book / Te s t S e r vl e t . d o " >

500 PLN

Kwota


Dane poprawne?



Rysunek 3.70. Formularz z wyszarzonymi obiektami — brak dostępu do opcji

Tylko Klienci VIP mogą wysyłać darmowe SMS Brak dostępu W prowadź nr telefonu:

Treść wiadomości

Wyślij |

Rozdział 3. ♦ Typy testów

117

Listing 3.14. Kodformularza z zastosowaniem opcji disabled

Tylko Kl i e n c i VIP mogą wys yłać darmowe SMS Brak dos t ę pu

Wprowadź n r t e l e f o n u : < / p > < i n p u t t y p e = " t e x t " d i s a b l e d name="smsTel efon" / >

Tr eść wi adomości < t e x t a r e a name="smsTresc" d i s a b l e d col s="20" rows="5">Treść SMS ^
< i n p u t t ype =" s u b mi t " d i s a b l e d v a l u e = " Wy ś l i j " / >

Listing 3.15. Kodformularza zmodyfikowany za pomocą narzędzia Fiddler — usunięcie opcji disabled

< f o n t s i z e = " 3 " c o l o r = " b l a c k " f a c e = " A r i a l "> Tylko Kl i e n c i VIP mogą wys yłać darmowe SMS Brak d o s t ę p u - na pewno?

Wprowadź n r t e l e f o n u :

< i n p u t t y p e = " t e x t " name="smsTel efon" / >

t r e ś ć wiadomości

< t e x t a r e a name="smsTresc" c ol s =" 20 " rows="5"> Tr e ś ć SMS < / t e x t a r e a > < b r > < i n p u t t ype = " s u b mi t " v a l u e = " Wy ś l i j " / >



Rysunek 3.71. Aktywacja przycisku i edycji pól na formularzu na skutek ataku

Tylko Klienci VIP mogą wysyłać darm owe SMS

Brak dostępu - na pewno? Wprowadź nr tołofomr 100-200-300 Treść wiadomości MaK dostęp do tej opcjij

Wyślij

3.2.3. Testy przenośności kodu — testy instalacji Weryfikacja przenośności kodu stanowi test niefunkcjonalny, aczkolwiek istotny z punktu widzenia powszechnego udostępnienia gotowego produktu lub uruchomienia systemu na docelowym środowisku produkcyjnym. Oprogramowanie zwykle powstaje w sposób modułowy, tj. taki, w którym fragmenty kodu pisane są przez różnych pro­

118

Testowanie oprogramowania. Podręcznik dla początkujących

gramistów. Bezspornie należy przyjąć, że obowiązkiem programisty jest uruchomić własny kod w celu podstawowej jego weryfikacji przed wgraniem do repozytorium. W tym miejscu ujawnia się pierwszy argument przemawiający za wykonaniem testów przenośności. Koderzy realizują self-test w spersonalizowanym środowisku przysto­ sowanym do własnych potrzeb, które niekoniecznie musi odpowiadać pełnym wyma­ ganiom środowiska produkcyjnego (różnice w konfiguracji, wersji serwera aplikacji, wersji serwera bazy danych etc.). Istnieje również duże prawdopodobieństwo, że pro­ gramiści uczestniczący w projekcie mają różnorodnie przygotowane własne środowiska pracy. Zdarza się, że koderzy używają wspólnie pewnych komponentów środowiska, np. serwera WWW, bazy danych. Niemniej jednak nadal jest to środowisko deweloper­ skie i nie można przyjąć, że ma charakter stabilny i stały. Ostatecznie gotowy produkt budowany jest w oparciu o łączny materiał przygotowany przez wszystkich programistów. Testy przenośności kodu polegają na wdrożeniu materiału przygotowanego przez ze­ spół produkcyjny w niezależnym środowisku, które spełnia formalne wymogi. Każda aplikacja powinna mieć wydaną rekomendację o warunkach, jakie musi spełniać śro­ dowisko, aby umożliwić uruchomienie i poprawną pracę systemu. Taka specyfikacja może być przygotowana na różnym poziomie szczegółowości w zależności od ro­ dzaju aplikacji. Inaczej będzie ona wyglądała dla aplikacji produkowanych na urzą­ dzenia nawigacji samochodowej, inaczej dla systemów klasy enterprise, a jeszcze inaczej dla oprogramowania pudełkowego. Rolą testera jest poddanie próbom przenośności aplikacji, tj. jej uruchamialności na różnych urządzeniach (np. nawigacje), w różnych wersjach systemu operacyjnego, we wspieranych przeglądarkach internetowych itp. Testy można uznać za pozytywne, jeżeli oprogramowanie da się uruchomić na różnych urządzeniach, serwerach etc. przy zachowaniu zgodności z wydaną rekomendacją dotyczącą środowiska. Nie można oczekiwać, że program będzie działał w pełni po­ prawnie, jeżeli uruchomimy go na urządzeniu spoza listy referencyjnej lub w przeglą­ darce, której formalnie system nie obsługuje. Wbrew pozorom to, co zostało uruchomione w środowisku deweloperskim, nieko­ niecznie udaje się wdrożyć produkcyjnie. Testy przenośności mają to zweryfikować. Problemy z przenośnością aplikacji mogą wynikać z błędów zaszytych bezpośrednio w kodzie, z niuansów w konfiguracji dla nieco innych serwerów, nieścisłości lub wady instrukcji wgrania itp. Dokumentacja wdrożenia również podlega ocenie i weryfikacji. Nie może zawierać błędów merytorycznych. Testy przenośności powinny być wykonywane na niezależnym środowisku, tj. innym niż używane do produkcji oprogramowania.

3.2.4. Testy ergonomii systemu informatycznego Przez pojęcie „ergonomia systemu informatycznego” należy rozumieć optymalne do­ stosowanie jego funkcjonalności do predyspozycji i cech psychofizycznych użytkow­ ników. W procesie produkcji oprogramowania duży nacisk kładzie się na realizację zdefiniowanych funkcjonalności, jednocześnie przywiązując mniejszą wagę do tego, w jaki sposób z poziomu interfejsu użytkownika to się odbywa. Projektanci i progra­ miści skupiają się na tym, aby zaspokoić oczekiwania wynikające z wymogów bizne­ sowych. W tym celu kierują siły i środki na realizację logiki funkcji wraz z niezbędnymi

Rozdział 3. ♦ Typy testów

119

modyfikacjami GUI. Załóżmy, że postawione jest wymaganie dodania nowej opcji do li­ sty rozwijanej w menu aplikacji. W którym miejscu programista dostawi nową wartość? Jeżeli w projekcie nie będzie miał literalnego zapisu o lokalizacji, z pewnością doda ją na końcu listy menu. Czy implementując kod, zastanowił się, jak często ta opcja będzie używana? Mam śmiałość wątpić. Może lepszym rozwiązaniem byłoby przesunięcie no­ wej opcji na jedną z górnych pozycji z uwagi na intensywność jej używania? Testy ergonomii systemu są trudne do wykonywania z racji tego, że testerzy weryfi­ kują aplikacje przeznaczone dla różnych — często zupełnie obcych — branż. Ponadto bardzo trudno odnieść się do ergonomii, pracując (testując) jedynie z nową funkcjo­ nalnością. Ergonomia odnosi się do całego systemu, dlatego też testy „wygody funk­ cjonalnej” powinny wykraczać poza nowo implementowany obszar. Ignorując tę za­ sadę, będzie bardzo trudno ocenić, czy nowa opcja, moduł w aplikacji jest utrzymany w przyjętej konwencji. Często zdarzają się sytuacje, gdzie mimo poprawności merytorycznej funkcjonalności zgłaszane są co do niej błędy. Analizując treść owych zgłoszeń, znajdziemy w nich zapisy mniej więcej tego typu: ♦ proszę o zmianę nazwy i kolejności przycisków; ♦ proszę o przesunięcie pola oraz zmianę jego wielkości; ♦ proszę o wprowadzenie listy rozwijanej zamiast wyboru za pomocą obiektu radio button; ♦ proszę o zmianę wielkości i koloru czcionki; ♦ proszę o przesunięcie pozycji w menu; ♦ proszę o zmianę skrótu klawiszowego do opcji; ♦ proszę o zwiększenie/zmniejszenie grafiki, tabeli itp.; ♦ proszę o zmianę treści i formy komunikatu; ♦ etc. W praktyce zamówiona opcja działa, ale jej obsługa nie do końca odpowiada użyt­ kownikowi końcowemu. Interfejs użytkownika w pewnych okolicznościach może okazać się niewygodny lub wręcz irytujący w użyciu. Bywa, że przeprowadzenie „sil­ nych” testów ergonomii jest poza zasięgiem możliwości testera. Wynika to z utrwalo­ nych nawyków i przyzwyczajeń kontrolerów jakości dotyczących obsługi aplikacji, braku zrozumienia branży oraz niechęci programistów do wprowadzania zmian „ko­ smetycznych”. Nieznajomość dziedziny, którą obsługuje oprogramowanie, może wpły­ nąć na odmienne wyobrażenie funkcjonalności, niż było intencją zamawiającego. Problem pogłębia jawna niechęć programistów do realizowania poprawek zgłasza­ nych pod flagą ergonomii. Zwykle koder powie: „Przecież działa, nie mam czasu na pierdoły”. Niemałym problemem w zachowaniu spójności jest fakt realizacji kodu przez kilku różnych programistów, gdy każdy z nich ma inne wyobrażenie w kwestii interfejsu użytkownika. Po połączeniu kodu w całość może się okazać, że pod wzglę­ dem ergonomii moduły nie do końca do siebie pasują. Programista A przygotuje komu­ nikaty walidacyjne w kolorze zielonym, a jego kolega na innym formularzu w barwie

120

Testowanie oprogramowania. Podręcznik dla początkujących

niebieskiej. Z kolei inny koder ostrzeżenia wyświetla w tonie czarnym, a cała reszta systemu podaje alerty w kolorze czerwonym i dodatkowo w ramce. Podstawowe testy ergonomii powinny obejmować: ♦ weryfikację, czy wszystkie komunikaty i ostrzeżenia w całym systemie zachowują spójną konwencję; ♦ weryfikację spójności etykiet; ♦ weryfikację nazewnictwa i układu przycisków, np. czy przyciski Akceptuj i Anuluj są zawsze w takiej samej kolejności;

♦ weryfikację, czy komponenty, np. lista rozwijana, pola tekstowe, są optymalnie dobrane i poprawnie zaimplementowane; ♦ weryfikację układu menu; ♦ ocenę skuteczności i przydatności skrótów klawiszowych (ang. hotkey); ♦ ocenę konsekwentnego wdrażania dodatkowych elementów, np. podpowiedzi dla pól; ♦ weryfikację obsługi klawiszy na formularzach, np. ENTER;

♦ ocenę ułatwień dla użytkownika, np. automatyczne podpowiadanie 00 po separatorze dziesiętnym, sam separator;

♦ ocenę użyteczności wzorców do przeszukiwania danych (filtry); ♦ ocenę potrzeby stronicowania danych; ♦ weryfikację rozkładu elementów i grafiki; ♦ wielokrotne powtarzanie tej samej czynności (wywołanie i użycie tej samej funkcji); ♦ etc. Komunikaty zwracane użytkownikowi w wyniku jego interakcji z systemem lub błę­ dów wewnętrznych są nieodzownym elementem aplikacji. Niezmiernie istotne jest utrzymanie jednolitej konwencji prezentacji takowych treści. Załóżmy, że przyjęto, że wszystkie informacje walidacyjne będą prezentowane w kolorze czerwonym, w okre­ ślonym kroju czcionki bezpośrednio pod polem, którego dotyczą. Ergonomia wyma­ ga, aby wszystkie tego typu zdarzenia były obsługiwane w założony powyżej sposób. Niedopuszczalne jest zmienianie czcionki oraz lokalizacji prezentowania komunikatu. Wszystkie odchylenia od wytycznych należy traktować jako błąd, pomimo że pod względem funkcjonalności wszystko działa. Rysunki 3.72 i 3.73 pokazują dwa for­ mularze tego samego systemu, które w odmienny sposób prezentują komunikaty walidacyjne. Jest to złamanie zasady ergonomii. Równie istotna jest sama treść prezen­ towanej informacji. Należy pamiętać, że to, co jest zrozumiałe dla umysłu programisty i w pewnym stopniu do zaakceptowania dla testera, dla docelowego użytkownika może być zupełnie niezrozumiałe. Użytkownika nie interesują wyjątki, klasy i inne techniczne problemy. Do raportowania i zbierania danych technicznych powinny służyć logi. Od­ biorca docelowy musi otrzymać czytelny i jasny komunikat, który jest w stanie zro­ zumieć i zinterpretować.

Rozdział 3. ♦ Typy testów

Rysunek 3.72. Zachowanie ergonomii dla komunikatów walidacyjnych

121

H isto ria d o ład o w a ń - F iltr o peracji W y b ie rz ra c h u n e k o b c ią ż a n y P o daj n r te le fo n u

Błędny nr telefonu(i)

P o daj kw otę doła d o w a n ia :

S o rtuj po: kwota

102030405000000 100-200-300-400

>= - -100

Niepoprawna kwota(!)

*

W yko naj akcję | Szukaj |

H isto ria d o ład o w a ń - F iltr o p e ra cji W y b ie r z ra c h u n e k o b c ią ż a n y

102030405000009 100-200-300-400

Podaj n r te le fo n u :

B tę d n y n r t e le f o n u j!)

P o d a j kw otą do ła d o w a n ia

- -100

PLNI Niepoprawna kwota(!)

S o rtuj po: kwota

W yko n aj akcję

Szukaj

Rysunek 3.73. Złamanie zasad ergonomii i estetyki dla komunikatów walidacyjnych Wystąpił błąd wewnętrzny aplikacji. Spróbuj ponownie za kilka minut. ORA-12154: TNS: could not resolve service name. Powyższa treść komunikatu nigdy nie powinna być ujawniona w interfejsie użytkownika, tj. powinna być „obcięta” o szczegóły techniczne. Spójność nazewnictwa jest istotna z punktu widzenia jakości i kultury obsługi programu i nie znajduje uzasadnienia w trudnościach technicznych. Jeżeli w systemie przyjęto, że polska waluta będzie reprezentowana przez PLN , to nie powinno się zdarzyć, że na jakimś formularzu wystąpi znak zł . Analogicznie należy postąpić z separatorem dziesięt­ nym i formatem kwoty. W całym systemie musi być zastosowane spójne rozwiązanie. Niedopuszczalne jest równoległe stosowanie znaku kropki (.) i przecinka (,). Rysunek 3.74 i rysunek 3.75 przedstawiają dwa formularze, które we wzajemnej relacji nie zachowują ergonomii.

Rysunek 3.74. Formularz doładowania telefonu — zastosowany separator dziesiętny to przecinek

122

Testowanie oprogramowania. Podręcznik dla początkujących

Rysunek 3.75. Formularz doładowania telefonu — zastosowany separator dziesiętny to kropka

Kanonem ergonomii systemów informatycznych jest konsekwentna polityka rozmiesz­ czania i nazywania przycisków/odnośników odpowiadających za akcję. Załóżmy, że przyjęta została następująca konwencja w całym systemie dla trzech przycisków (rysunek 3.76): ♦ A nuluj — pozwala na wycofanie się z formularza i anulowanie procesu, pierwszy od lewej; ♦ Czyść — pozwala na wyczyszczenie danych z formularza, pozycja środkowa; ♦ Zatwierdź — pozwala za zatwierdzenie procesu, trzeci w kolejności. Zgodnie z powyższym założeniem wszystkie wymienione przyciski powinny być na­ zwane i zgrupowane w kolejności: Anuluj/Czyść/Zatwierdź. Zatem za niedopuszczal­ ne należy uznać występowanie ich w zmienionym szyku oraz pod odmiennymi na­ zwami. Wyobraźmy sobie sytuację, kiedy na jednym z formularzy przycisk Anuluj zaimplementowany jest w standardowym miejscu przycisku Czyść (rysunek 3.77). Użytkownik kierujący się nawykiem może użyć środkowego przycisku do zresetowania formularza, a spotka go niespodzianka, gdyż faktycznie wykona akcję anulowania. Teoretycznie system zachował się poprawnie, akcja była wykonana zgodnie z opisem obiektu. Tego rodzaju „pułapki” czyhające na użytkownika mogą konsekwentnie zwiększać jego poziom irytacji. Rysunek 3.76. Ergonomia przycisków akcji

Doładowanie telefonu W y b ie rz rachunek obciążany

100-200-300

Podaj kwotę doładowania

200

W ybierz akcję I Anuluj

Rysunek 3.77. Złamanie zasad ergonomii

102030405000009 ▼

Podaj nr telefonu:



I Czyść |[ ¿atwierdź~|

Edycja zlecenia doładowania W ybie rz rachunek obciążany

102030405000009 -

Podaj nr telefonu: Podaj kwotę doładowania

Wybierz akcję

PLN

Czyść [ [ Anuluj 1 Zatwierdź"

Rozdział 3. ♦ Typy testów

123

Bywa, że zastosowane przez programistę rozwiązanie pomimo poprawnego działania nie jest najszczęśliwiej dobrane pod względem użyteczności. Przyjrzyjmy się formu­ larzowi z rysunku 3.78, gdzie wybór rachunku obciążanego odbywa się za pomocą obiektu radio button. Zasadniczo bardziej korzystnym rozwiązaniem jest wprowadzenie listy rozwijanej. Po pierwsze: w ten sposób zmniejszymy liczbę detali (elementów) strony. Po drugie: z pewnością przyspieszy to obsługę formularza (rysunek 3.79). Strona stanie się bardziej przyjazna pod względem użyteczności.

Rysunek 3.78. Wybór rachunku za pomocą obiektu radio button

Historia doładowań - Filtr operacji 1(wni>i0.rr000009

W y b ie rz rtic h u n e k o b c ią ż a n y

«po.'vodosofiooooon d05060700000007

P odaj n r to ło fo n ir P odaj kw oto do ła d o w a n ia S o i luj po. kwota

Wybór rachunku za pomocą listy rozwijanej

PLN

»

WykonaJ akcję

Rysunek 3.79.

> -

Szukuj

H istoria doładow ań - Filtr operacji W y b ie rz ra c h u n e k o b c ią ż a n y

| 102030405000009 -

Podaj n r telefonu: Podaj kw otę doładow ania:

S o rtuj po: kwota

W ykonaj akcję

>= ▼

^ | Szukaj, |

Instytucje mające na uwadze komfort pracy z systemem informatycznym wprowa­ dzają rozwiązania wspomagające jego obsługę. Przykładem jest implementacja me­ chanizmu dopełniania zerami wartości po separatorze dziesiętnym (dla pól z kwotami). Użytkownik wprowadza wartość 100 lub 100,5, a system automatycznie przekształca ciąg odpowiednio do postaci 100,00 i 100,50 (rysunki 3.80 i 3.81). Spotkałem się z aplikacj ą funkcjonującą produkcyjnie, która nie wykonuje takiego dopełnienia i po poda­ niu wartości 100,1 zatrzymuje operację na etapie walidacji danych formularza. Jest to niezwykle irytujące! W sytuacji kiedy system posiada wypracowany mechanizm „dopełniania zerami”, implementowanie go dla wszystkich analogicznych pól zapewnia ergonomię. Przez analogię problem należy przełożyć na pozostałe funkcje ułatwiające obsługę np. podpowiedzi dla pól i opcji formularza, tzw. „helpów”. W przypadku kiedy aplikacja zapewnia określony wachlarz wskazówek dla użytkownika, taki standard po­ winien być naniesiony również na nowo produkowane moduły/funkcje. Należy wziąć pod uwagę, że użytkownicy zapewne przywykli do tego typu dodatków i z pewno­ ścią ich brak zostanie zauważony i oceniony. Powszechnie znaną prawdą jest, że wszel­ kie zmiany na „gorsze” są niechętnie akceptowane.

12 4

Testowanie oprogramowania. Podręcznik dla początkujących

Rysunek 3.80. Wprowadzenie kwoty z wartością dziesiętną, tj. jedno miejsce po przecinku

E d yc ja zlecen ia d o ła d o w a n ia W y b ie rz ra c h u n e k o b c ią ż a n y

102030405000009 -

P o daj n r te le fo n u :

100-200-300

P o daj kw o tą d o ła d o w a n ia :

100,5

W y b ie rz akcję I Anuluj I I Czyść

Rysunek 3.81. Dopełnienie wartości dziesiętnej na drugiej pozycji po przecinku

PLN |

Zatwierdź |

Potwierdź doładowanie telefonu Rachunek obciążany: Nr telefonu:

100-200-300

Kwota doładowania: Dane poprawne?

102030405000009

[ 1tX) 5 0 1U N | AKCEPTUJ

Ważnym elementem dla ergonomii systemu jest zagwarantowanie stronicowania da­ nych. Obecnie aplikacje pracują z dużą ilością danych i wyświetlanie kilkuset czy nawet tysięcy wierszy na jednej stronie może okazać się trudne w obsłudze. Nie zaw­ sze potrzeba stronicowania jest oczywista na etapie projektowania. Niemniej jednak w fazie testów i pracy z dużą ilością danych zapewne zostanie ona ujawniona. Niestety często będzie trudno przekonać programistę do wdrożenia omawianego rozwiązania, gdyż nie będzie ono miało literalnego potwierdzenia w wymaganiach (projekcie). Na­ tomiast bezdyskusyjnie stronicowanie winno być powtarzane dla nowo powstałych funkcjonalności, jeżeli zastosowano je w dotychczasowych (konsekwencja). Rozbudowane interfejsy użytkownika umożliwiają przeszukiwanie danych w oparciu 0 zróżnicowane kryteria. Jak wiadomo, z tych samych danych można uzyskać różne in­ formacje, sterując sekcją WHERE zapytania SQL. W tym celu powoływane są filtry, na których ustala się pożądany wzorzec przeszukiwania i prezentacji danych. Ergonomia wymaga, aby możliwości i układ graficzny tego typu filtru były powtarzane w każ­ dym kolejnym miejscu jego występowania. Potrzeby biznesowe wymagają filtrowania danych w wielu różnych miejscach systemu. Komfort użytkowania takiej funkcji zależy od konsekwencji, z jaką jest ona implementowana. W istocie zdarzają się sytuacje, kiedy filtr z określonej opcji nie pasuje idealnie do drugiej. Niemniej jednak należy zacho­ wać maksymalną spójność i analogię we wszystkich instancjach tego rozwiązania na obszarze całego systemu. Większość aplikacji — niezależnie czy internetowych, czy desktopowych — obsłu­ giwana jest przez użytkowników za pomocą kursora i myszy. Niestety programiści i wtó­ rujący im testerzy zapominają o narzędziu, jakim jest klawiatura. Jeżeli w systemie przyjęte zostało, że klawisz ENTER będzie służył do zatwierdzania akcji, czyli działał analogicznie jak dedykowany temu przycisk graficzny, to takie rozwiązanie musi funkcjonować w całej aplikacji. Załóżmy, że wprowadzam kwotę doładowania w polu 1 zarazem jest to ostatni punkt formularza, a następnie wciskam ENTER. Jako użyt­ kownik spodziewam się, że w ten sposób potwierdziłem formularz i przeszedłem do kolejnego kroku. W innej sytuacji wpisuję kod autoryzacyjny SMS w celu potwier­ dzenia operacji w serwisie transakcyjnym, a następnie wciskam ENTER. Ponownie oczekuję wykonania akcji zatwierdzenia. Przyjęcie założenia, że ENTER będzie zatwier-

Rozdział 3. ♦ Typy testów

125

dzał akcje, zobowiązuje do konsekwentnego rozpropagowania tego rozwiązania w całym systemie (przypisanie domyślnej akcji do klawisza). Niedopuszczalne jest umożliwie­ nie zalogowania się do systemu przy zatwierdzeniu klawiszem, ale już ENTER przy potwierdzaniu kodem SMS „nie działa”. Kolejnym problemem związanym z obsługą klawiatury są przypisania akcji menu do określonego skrótu klawiszowego (ang. hotkey). Bardzo często zaniedbywana jest pielęgnacja tej funkcji, co przekłada się na wadliwe działanie skrótów klawiszowych w późniejszych wersjach systemu. Częstym błędem jest dublowanie kombinacji klawiszy, tj. jeden skrót przypisany jest do dwóch lub więcej opcji. Flagowym miejscem, na którym „wykładają” się programiści, jest ob­ sługa klawisza TAB. Przy założeniu, że ma on umożliwić poruszanie się pomiędzy polami formularza, to przede wszystkim: ♦ musi on działać poprawnie, tj. faktycznie przenosić kursor po polach formularza, a może zdarzyć się tak, że w wyniku błędu w kodzie przerzuci użytkownika w zupełnie inne miejsce systemu; ♦ jeżeli działa, to powinien przenosić kursor kolejno po polach, a często w wyniku modyfikacji formularza (dodawanie nowych elementów) akcja jest zaburzona, gdy równolegle nie utrzymano standardu obsługi klawisza. 0 problemie ergonomii elementu, jakim jest menu, wspominałem nieco wyżej. Warto nadmienić i przypomnieć, że samo działanie opcji nie wystarcza. Liczy się także przejrzystość, kolejność, estetyka i jednoznaczność nazw/etykiet. Z natury GUI wynika, że zawiera szereg elementów, których graficzne użycie przeło­ ży się na zrealizowanie określonego procesu bez jawnego sterowania nim z wiersza poleceń. Graficzny interfejs użytkownika ułatwia obsługę systemu, tj. ma być funk­ cjonalny, łatwy, komfortowy i estetyczny (w kontrze do linii komend). Zatem powinien posiadać poprawnie wdrożony layout (ustaloną konstrukcję graficzną). Z reguły tester nie ocenia koncepcji graficznej, lecz jej implementację, np. czy wszystkie ikony są poprawnie wyświetlane, czy elementy nie zachodzą na siebie, czy flagi zmiany języka prawidłowo realizują swoją funkcję etc. Liczba wymaganych punktów kontroli w celu oceny ergonomii aplikacji zależy od jej charakteru i przyjętego standardu, jaki ma spełniać. Utrzymanie estetyki, spójności 1konsekwencji w aplikacji to elementy świadczące o dużej dojrzałości zespołu produk­ cyjnego. Wysoka ergonomia systemu wzbudza zaufanie i daje podstawy do przypusz­ czeń, że logika programu będzie również dobrej jakości.

3.3. Testy regresywne Testy regresywne to działania polegające na weryfikacji istniejących funkcjonalności systemu, które zostały wytypowane jako potencjalnie zagrożone na skutek modyfika­ cji kodu. Wspomniana modyfikacja kodu może dotyczyć bezpośrednio wskazanego elementu, np. w wyniku dodawania nowych pól na formularzu, lub elementów po­ bocznych, pośrednich, np. procedury, która jest wywoływana w jakiejś opcji formularza. Systemy informatyczne rozwijają się na skutek dostosowywania ich funkcjonalności

126

Testowanie oprogramowania. Podręcznik dla początkujących

do bieżących potrzeb biznesowych. Ów rozwój najczęściej polega na dodawaniu no­ wych opcji, modyfikacji istniejących lub wygaszaniu części funkcji. Testy regresywne mają wykazać, że zmiany dokonane w kodzie nie „uszkodziły” dotychczasowych funk­ cjonalności. Rozważmy sytuację, w której modyfikowany jest moduł kartoteki klientów, tj. dodajemy kilka nowych walidacji dla istniejących pól formularza oraz implemen­ tujemy nowy element, tj. nowe pole. Oprócz weryfikacji działania formularza pod kątem użycia nowych walidacji należy również sprawdzić, czy modyfikacja kodu nie rzutuje negatywnie na globalne działanie kartoteki klienta, np. na dodawanie/edycję danych podmiotu. Reasumując, formularz powinien zachowywać się poprawnie w niezmie­ nionym obszarze działania przy jednoczesnym uwzględnieniu „wprowadzonych no­ wości”. Testy regresywne polegają na ponownej weryfikacji już przetestowanego fragmentu lub całości aplikacji po wprowadzeniu w niej modyfikacji. Wspomniana modyfikacja może dotyczyć kodu programu lub środowiska, w którym został on osa­ dzony (uruchomiony). Ze względu na powtarzalność wykonywania ścieżek testowych testy regresywne dobrze nadają się do automatyzacji. Testy regresywne można wyko­ rzystywać do oceny i potwierdzania zachowania systemu w aspekcie cech funkcjo­ nalnych, jak i niefunkcjonalnych. Kłopotliwą kwestią nieustannie pozostaje określenie promienia kręgu, jaki testy regresywne powinny zataczać. Prawdą jest, że czynności związane z oceną i weryfikacją stanu oprogramowania kosztują. Naturalnym zachowaniem jest dążenie do optymalizacji kosztów produkcji. Zatem zespół testów powinien liczyć się z naciskami na ograni­ czenie czasu poświęconego na testy regresywne. Z drugiej strony, wykonanie ich zbyt pobieżnie może spowodować nieporównywalnie większe koszty w sytuacji przeoczenia błędu, który ujawni się bezpośrednio w środowisku produkcyjnym. Aplikacji nie można testować w nieskończoność. Przeszacowanie pracochłonności na testy regresywne również nie jest dobre z punktu widzenia globalnego wyniku ekonomicznego projek­ tu. Ponownie wszystko sprowadza się do oszacowania ryzyka i optymalnego dopaso­ wania rodzaju oraz zakresu testów do sytuacji. Niestety złotego środka w projektowaniu tegoż rodzaju testów nie ma. Wydaje się, że u podstaw sukcesu leży doświadczenie i bardzo dobra znajomość systemu poparta kompetencjami z zakresu użytej techno­ logii. Bywa, że drobne zmiany w kodzie wymagają dużego wysiłku ze strony testów. Zdarzają się też odwrotne sytuacje. Dużą trudnością będzie przekonanie przełożonego o konieczności wykonania testów regresywnych, których czas kilkukrotnie przekracza liczbę roboczogodzin poświęconych na implementację modyfikacji. Niemniej jednak za takim rozwiązaniem może przemawiać duże ryzyko związane z danym elementem (modułem). Doświadczony tester, który dobrze zna i rozumie system, wie, które kom­ ponenty są naznaczone dużą „błędogennością”. Podwyższone ryzyko może być w y­ nikiem nie najlepszego wykonania modułu już na etapie powoływania go do życia. Historia pracy, obsługi kodu komponentu także wiele mówi o potencjalnym ryzyku. Wyobraźmy sobie sytuacj ę, w której kod elementu był modyfikowany przez kilku programistów i w dodatku część z nich już nie pracuje w zespole. Przechodzenie źródła kodu przez wiele rąk, szczególnie kiedy jest to skomplikowane rozwiązanie, z pewno­ ścią podnosi ryzyko wystąpienia błędu. W tym miejscu należy przypomnieć, że testy białej skrzynki umożliwiają weryfikację utrzymania standardu programowania przez koderów.

Rozdział 3. ♦ Typy testów

127

Złudne, a zarazem zgubne w skutkach może być poczucie, że wprowadzona modyfi­ kacja nie wymaga uruchomienia testów regresywnych. Takie mylne przekonanie może być wynikiem braku widocznych różnic w obsłudze danej funkcjonalności z punktu widzenia użytkownika. W aspekcie GUI wszystko pozostaje „po staremu”, lecz może zmienić się w potężny sposób logika uruchamiana pod warstwą prezentacji np. w celu poprawy wydajności. Standardowo testy funkcjonale mogą się odbyć poprzez po­ równanie wyników otrzymanych „po staremu” i „po nowemu”. Niemniej jednak jest to niewystarczający test. Zakres prac należy poszerzyć o obsługę mniej typowych i powszechnych sytuacji oraz skrupulatnie przyjrzeć się funkcjonowaniu modułów pobocznych (zależnych). Oczywiście istnieją uzasadnione sytuacje, kiedy można istotnie zmniejszyć testy regresywne lub je w ogóle zarzucić. Załóżmy, że w jakimś pakiecie bazy danych ORACLE dodana jest nowa procedura z silną logiką. Testy regresywne wspomnianego pakietu nie muszą być ultraskrupulatne, gdyż część kwestii sprawdzi kompilator, a pozostałe aspekty można zweryfikować na przykład poprzez porównanie kodu obu wersji pa­ kietu (aktualnego i poprzedniego). Porównanie kodu powinno dać odpowiedź, czy faktycznie dodano tylko nową procedurę, czy może pojawiły się jakieś nowości w in­ nych elementach pakietu. Jeżeli analiza wykaże, że zmodyfikowano „coś jeszcze”, będzie to oznaczało, iż nasz test regresywny „złapał programistę za rękę na gorącym uczynku” i powinien on wytłumaczyć się z zaistniałej sytuacji.

Jako ostateczną konkluzję należy przyjąć, że testy regresywne są konieczne, a ich za­ kres powinien być adekwatny do oszacowanego ryzyka.

Rozdział 4.

Wprowadzenie do projektowania testów Projektowanie testów odnosi się do opracowania przypadków testowych oraz okre­ ślenia warunków ich wykonania. Testy projektuje się w celu optymalnego zorgani­ zowania pracy, zapewnienia ich wiarygodności i użyteczności w sposób jak najbar­ dziej zbliżony do rzeczywistego użytkowania systemu. Czyli po prostu testy należy zorganizować w sposób jak najmniej kosztowny i jednocześnie zapewniający maksy­ malne bezpieczeństwo w rozumieniu jakości systemu. W jaki sposób zapewnić taką symbiozę? Otóż poprzez profesjonalne zaprojektowanie testów. Rysunek 4.1 obrazuje przypadek testowy dla kalkulatora, a konkretnie operacji ilo­ czynu wykonanego w technologii R E ST (wywołanie RESTful). Jako wartości począt­ kowe (x, y) dla weryfikacji operacji mnożenia podano x = 2, y = 2. Czy tak zaprojek­ towany test jest prawidłowy? Nie, jest to typowo akademicki przykład wadliwie wykonanego testu. Wrócimy do tego przykładu na dalszych kartach niniejszej publikacji. Rysunek 4.1. Test operacji mnożenia dla kalkulatora wykonanego w technologii REST (wywołanie RESTful)

Projektowanie testów Pierwszym krokiem powinno być zidentyfikowanie warunków testowych. Proces ten obejmuje określenie, co testujemy oraz czego potrzebujemy do zrealizowania testów. Oprzyjmy się na przykładzie. Dostajemy do testów nowy moduł już zaimplemento­ wany w istniejącej aplikacji, którą uprzednio mieliśmy okazję weryfikować (rozsze­ rzenie funkcjonalności). Moduł ma prezentować ma w formie graficznej i tabelarycznej zmiany kursu walut. Kursy walut mają być pobierane za pomocą usługi sieciowej (web service). Niezbędne do wykonania testów są: ♦ dostęp do usługi WS lub własny symulator systemu zewnętrznego; ♦ monitor TCP/IP do przechwycenia komunikacji oraz ewentualnego wstrzymania jej (timeout);

130

Testowanie oprogramowania. Podręcznik dla początkujących

♦ dodatkowy klient usługi, np. SoapUI; ♦ dokumentacja komunikacji pomiędzy systemami, np. WSDL; ♦ dokumentacja analityczna i projektowa implementacji; ♦ analiza i przygotowanie zestawu danych, które klient WS musi otrzymać, aby w pełni przetestować funkcjonalność; ♦ analiza i alokacja zasobów, np. weryfikacja, czy nie zachodzi potrzeba separacji testów funkcjonalności od głównego środowiska testów; ♦ rewizja potencjału kompetencji, tj. czy dysponujemy odpowiednio „wyszkolonymi” testerami i/lub w jaki sposób ewentualne luki merytoryczne uzupełnić. Zajęcie się powyższymi zagadnieniami stanowi pierwszą fazę projektowania testów. Na podstawie zgromadzonych informacji w postaci odpowiedzi na powyższe pytania należy poczynić i wypunktować istotne założenia wstępne, które stanowią podbudo­ wę do rozpoczęcia bardziej szczegółowych prac. Faza pierwsza powinna uzmysłowić, jakie problemy natury technicznej mogą nam sprawić kłopot oraz w jakim stopniu do­ tychczasowe zasoby (środowisko i ludzie) odpowiadają potrzebom projektu testowego. Kolejny etap projektowania testów poświęcony jest na wyspecyfikowanie przypad­ ków testowych. Wspomniana specyfikacja powinna uwzględniać dane wejściowe, warunki początkowe, oczekiwany rezultat oraz technikę wraz z narzędziami wyko­ nania testu. Pojedynczy przypadek testowy odnosi się do fragmentu aplikacji, np. spraw­ dzamy treść komunikatu walidacyjnego. Musimy dążyć do wywołania tej informacji, tzn. należy poprowadzić system tak, aby wymusić wyświetlenie komunikatu, który ujawnia się w ściśle zdefiniowanych okolicznościach. Po zdefiniowaniu celu opisujemy sekwencję zdarzeń i czynności w scenariuszu przypadku testowego. Celem przypadku testowego jest stworzenie warunków do potwierdzenia, że wyspecyfikowany frag­ ment (funkcjonalność) systemu działa zgodnie z oczekiwaniem. W analogiczny spo­ sób mnoży się przypadki testowe, tak aby uzyskać zbiór, który w pełni pokryje system testami. Należy dążyć do jak najbardziej wiernego zaprojektowania przypadków, tj. idealne jest osiągnięcie maksymalnego odwzorowania rzeczywistego stanu przypadków użycia uzupełnionego o niestandardowe wariacje. Przypadki testowe powinny wykra­ czać poza spodziewaną obsługę systemu w warunkach realnego użycia aplikacji. Za­ łożenia i treść merytoryczna przypadku są uzależnione od rodzaju wykonywanego testu — mogą to być np. testy bezpieczeństwa, testy funkcjonalne, testy wydajnościowe. Bardzo istotnym elementem jest szczegółowe i jasne wyspecyfikowanie oczekiwane­ go rezultatu, jaki powinniśmy otrzymać po wykonaniu przypadku. Brak tego opisu może spowodować, że wynik zostanie błędnie zinterpretowany i zaklasyfikowany jako poprawny. Należy pamiętać, że testy mogły zostać zaprojektowane przez inną osobą niż ta, która je wykonuje. Trzecim etapem jest ustalenie kolejności wykonywania przypadków testowych. Jest to krok wręcz strategiczny dla całego procesu testowania. Przypadki testowe powinny być zgrupowane ze względu na obszary systemu, których dotyczą, i konsekwentnie uło­ żone. Nie mogą być realizowane w sposób przypadkowy, gdyż ostateczny wynik mo­ że być osiągnięty z dużym opóźnieniem i/lub jego rezultat nie będzie odpowiadał sta­ nowi faktycznemu aplikacji. Kluczem, według którego ustala się kolejność, są:

Rozdział 4. ♦ Wprowadzenie do projektowania testów

131

♦ priorytety — pewne części aplikacji nie mogą zostać należycie zweryfikowane, jeżeli uprzednio nie nabierzemy pewności, że moduły, od których one zależą, funkcjonują prawidłowo (logika działania); ♦ zależności techniczne — istnieją okoliczności, które silnie uzależniają uruchomienie modułu od innego fragmentu aplikacji — nieefektywne jest rozpoczynanie gruntownych testów modułu drugiego, jeżeli nie jesteśmy przekonani, że element pierwszy spełnia wszystkie założenia techniczne (zależność techniczna, współdziałanie); ♦ ryzyko wystąpienia błędów krytycznych — praktyka wskazuje, że błędy lubią się kumulować, doświadczony tester jest w stanie „wyczuć”, które obszary winny być weryfikowane jako pierwsze w celu jak najszybszego wykrycia i usunięcia błędów krytycznych (w tym blokujących); ♦ poziom testów, np. regresywny, integracyjny, systemowy. Testy to czynność, która trwa w czasie. Planując przypadek testowy, należy oszacować czas jego wykonania, tj. jednej iteracji. Lista przypadków testowych powinna być uczciwie zrealizowana. Wymaga to określenia realnego czasu potrzebnego na wyko­ nanie przypadku. Błędem jest zakładanie, że przypadek zakończy się sukcesem po pierwszym wykonaniu. Harmonogram musi zakładać kolejne iteracje, gdyż z pewnością część przypadków będzie musiała być wykonywana wielokrotnie (powtarzana). Niedo­ szacowanie czasochłonności realizacji ogółu testów dla projektu skutkować będzie prze­ kroczeniem założonego budżetu lub wydaniem produktu o nie do końca pewnej jakości. Niniejszy rozdział poświęcony jest teoretycznym aspektom projektowania testów w opar­ ciu o techniki białej i czarnej skrzynki. Finalnie podsumujemy rozważania omówieniem kilku przykładów praktycznych.

4.1. Projektowanie testu w oparciu o technikę czarnej skrzynki Niniejszy podrozdział poświęcony jest projektowaniu przypadków testowych w oparciu o technikę czarnej skrzynki. Omówię niezmiernie istotne zagadnienie warunków brze­ gowych, wspomnę o klasach równoważności oraz weryfikacji stanu oprogramowania.

4.1.1. Wartości brzegowe Analizę i ustalenie wartości brzegowych wykonuje się w celu zaprojektowania testu celuj ącego bezpośrednio w krawędzie przedziału (warunku) z uwagi na to, że jest to miejsce szczególnie narażone na błędy. Omówię zagadnienie w oparciu o poniższe przykłady. Aplikacja zawiera filtr, który używa zakresu dat do zawężenia prezentowanych wyni­ ków (wyszukiwanie). Załóżmy, że filtr oferuje opcje wyszukiwania: bieżący miesiąc, bieżący rok, poprzedni rok. Trudno sobie wyobrazić, że tester będzie wprowadzał

132

Testowanie oprogramowania. Podręcznik dla początkujących

(generował) co najmniej 365x2 (2 lata — historia) wartości w celu weryfikacji za­ chowania aplikacji. Bywa, że warunek ilościowy nie jest jedynym i dodatkowo należy zróżnicować dane, co zwielokrotniłoby ilość wierszy. W tym celu należy posłużyć się analizą wartości brzegowych, tzn. maksymalnymi i minimalnymi wartościami, które będą wykorzystywane w decyzyjnym warunku filtra. Za datę wykonania testu przyjmijmy 23.11.2013. Opcje filtra zgodnie z założeniem powinny obejmować przedziały: ♦ „bieżący miesiąc” : — zakładamy, że nie pokazujemy danych „w przód” od daty bieżącej; ♦ „bieżący rok” : ; ♦ „poprzedni rok” : . Zastosowanie testu opartego na warunkach brzegowych wymaga przygotowania ze­ stawu minimalnych danych, które ujęte są w tabeli 4.1. Spreparowane dane ze szcze­ gólnym naciskiem na krawędzie przedziałów pozwolą na weryfikację logiki bez po­ siłkowania się dużym wolumenem danych. Tego typu test ma ocenić, jak zachowuje się aplikacja w momentach decyzyjnych. Oczywiście jeżeli naszym zamierzeniem jest dodatkowo sprawdzić dynamikę przeszukiwania oraz formę prezentacji wyniku, po­ winniśmy uzupełnić zakres i jakość danych. Tabela 4.1. Zakres danych (dat) do wykonania testu w oparciu o klasy równoważności Parametry filtra Daty

bieżący miesiąc

bieżący rok

poprzedni rok

31.12.2011 01.01.2012

01.01.2012

02.01.2012

02.01.2012

15.05.2012

15.05.2012

31.12.2012

31.12.2012

01.01.2013

01.01.2013

02.01.2013

02.01.2013

25.06.2013

25.06.2013

31.10.2013

31.10.2013

01.11.2013

01.11.2013

01.11.2013

02.11.2013

02.11.2013

02.11.2013

23.11.2013

23.11.2013

23.11.2013

24.11.2013

24.11.2013

25.11.2013

Idealnym przedmiotem rozważań o klasach równoważności są typowe przedziały liczb. Sklepy internetowe lub serwisy aukcyjne oferują funkcjonalność filtrowania przedmiotów, których cena znajduje się w zadanym przedziale (leżącym w zaintere-

Rozdział 4. ♦ Wprowadzenie do projektowania testów

133

sowaniu klienta). Załóżmy, że interesują nas przedmioty od 250 zł do 1200 zł. Zanim taka opcja zostanie udostępniona produkcyjnie, powinna być poddana weryfikacji. Idealnie do tego celu nadaje się test warunków brzegowych. Tabela 4.2 zawiera ze­ staw danych, który pozwoli na zrealizowanie tego typu testu. Tabela 4.2. Zestaw danych do testu warunków brzegowych od 250 do 1200

Kwota 249,99 250,00

250,00

250,01

250,01

500,10

500,10

1130,98

1130,98

1199,99

1199,99

1200,00

1200,00

1200,01

Pełny test wartości granicznych musi obejmować wartości: pierwszą niepoprawną, poprawną, drugą poprawną, przedostatnią poprawną, ostatnią poprawną, pierwszą błędną z drugiej strony (rysunek 4.2). Reasumując: określamy przedział , gdzie x i y to poprawne wartości graniczne. Test powinien obejmować wartości: Rysunek 4.2. Analiza warunków brzegowych

W ramach podstawowego kursu ISTQB poruszane jest zagadnienie „klasy równo­ ważności”, gdzie dane o podobnych cechach i charakterze grupuje się. To grupowanie oparte jest na mniemaniu, że dane zbliżone, pokrewne będą obsługiwane przez system w analogiczny sposób. Na tej podstawie tworzy się zarówno wartości poprawne, jak i niepoprawne, które użyte zostaną jako reprezentanci grupy (klasy równoważności). Poprawna klasa równoważności to taka, która powinna zostać przepuszczona przez system. Natomiast niepoprawna klasa równoważności powinna być odrzucana. Analizę wartości brzegowych można traktować jako rozszerzenie podziału na klasy równo­ ważności.

13 4

Testowanie oprogramowania. Podręcznik dla początkujących

4.1.2. Przejścia pomiędzy stanami Niegdyś testowanie przejść pomiędzy stanami systemu traktowałem z przymrużeniem oka. Zatem nie czyniłem większych wysiłków, aby postrzegać system przez pryzmat stanów, jakie przyjmuje. Sytuacja diametralnie uległa zmianie, kiedy zauważyłem bardzo irytujący błąd w oprogramowaniu nowo nabytego telewizora. Oprogramowanie wbudowane np. w automatyce przemysłowej powinno podlegać tego typu testom. Niemniej jednak tego rodzaju testy nie są wyłącznie zarezerwowane dla kodu zaszy­ tego w urządzeniach. Z powodzeniem można planować przypadki np. dla aplikacji internetowych. Wracając do telewizora. Oferuje on standardową funkcję przeskoku do interesującego nas kanału poprzez podanie jego numeru, np. z 4 na 46. Owa opcja działa znakomicie, 0 ile nie pomylę się we wpisywaniu wartości lub nie zmienię zdania w trakcie. Za­ łóżmy, że zamierzam skoczyć do kanału 57. Wybieram opcję na sterowniku (pilocie) 1 wpisuję 57. Jednak zanim potwierdzę akcję lub telewizor sam sfinalizuje zadanie, wycofuję się z opcji (zamykam funkcję). Za kilkanaście sekund ponownie wywołuję tę samą opcję w celu wybrania jednego z dalszych kanałów. Niestety czeka mnie roz­ czarowanie, gdyż oprogramowanie (telewizor) nie zmieniło stanu, tj. nie wyzerowało uprzednio wprowadzonych wartości i powtarza domyślnie wartość 57. Funkcja skoku umożliwia podanie czterech liczb (np. 5 7 __ ). W związku z brakiem możliwości edy­ cji już wprowadzonych muszę dopisać jeszcze dwie (dopełnić do czterech, np. 5 7 1 1), aby zresetować wszystkie pozycje (_______ ) i wpisać interesującą wartość, np. 27 (2 7 __ ). To był punkt zwrotny, w którym wzmocniłem czujność i zacząłem przy­ wiązywać większą wagę do stanu, jaki przyjmuje aplikacja. Na rysunku 4.3 przedstawiłem domniemany algorytm działania omawianej funkcji. Spodziewałem się, że w chwili wycofania się z opcji w momencie wprowadzania nu­ meru kanału oprogramowanie zmieni stan na pierwotny, tj. wyzeruje wartości tak, aby po ponownym wywołaniu funkcji można było bez przeszkód wpisać nową war­ tość. Tak się niestety nie dzieje. Jest to o tyle ciekawe, że w momencie pełnej ścieżki, tj. przeskoku do wybranego kanału, stan jest zerowany. Dodatkowym powodem do irytacji jest brak możliwości edycji poszczególnych pozycji, tzn. po wprowadzeniu 5 7 nie można cofnąć się i zmienić np. na 5 8 __ . Rysunek 4.3. Przykładowy diagram zmiany stanu dla funkcji wybierania numeru kanału w telewizorze

Rozdział 4. ♦ Wprowadzenie do projektowania testów

135

Projektuj ąc testy uwzględniające przej ścia pomiędzy stanami, należy starać się pokryć stosunkowo wiernie ścieżki użytkowania oprogramowania. Testy powinny również wy­ eliminować problemy martwego kodu i zapętleń.

4.1.3. Projektowanie testu w oparciu o przypadki użycia Przypadki użycia (ang. use cases) są powszechnie wykorzystywane do opisu wymagań funkcjonalnych. Odnoszą się one do interakcji pomiędzy systemem a użytkownikiem i są opisem sekwencji kroków (zdarzeń). Przypadek użycia powinien definiować główną (najbardziej optymalną) ścieżkę obsługi bez wnikania w aspekty implementacji. Oprócz głównego przebiegu akcji możliwe jest zdefiniowanie ścieżki alternatywnej (mniej prawdopodobnej, choć przypuszczalnej). Przypadek użycia musi opisywać, w jaki spo­ sób aplikacja powinna być obsługiwana (używana), aby osiągnąć zadany cel. Przykład przypadku użycia (przebieg główny): 1. Użytkownik loguje się do serwisu transakcyjnego za pomocą loginu i hasła. 2. Użytkownik zostaje zalogowany. 3. Wybiera opcję doładowanie telefonu. 4. Wprowadza kwotę doładowania, numer telefonu oraz wybiera numer rachunku obciążanego. 5. Zatwierdza operację przyciskiem Doładuj (krok 1. z 3). 6. Weryfikuje dane (krok 2. z 3). 7. Autoryzuje transakcję kodem SMS (krok 3. z 3). 8. Transakcja zostaje przyjęta. 9. Wylogowanie manualne (przez użytkownika). Przykład przypadku użycia (ścieżka alternatywna 1): 8a. Autoryzacja się nie powiodła. 8a1. Powrót do kroku 7. (druga próba autoryzacji). Przykład przypadku użycia (ścieżka alternatywna 2): 9a. Wylogowanie automatyczne (długa bezczynność użytkownika). Testy zaprojektowane w oparciu o przypadki użycia znajdują bardzo dobre zastoso­ wanie podczas wykonywania testów akceptacyjnych. Definicja testów jest bardzo zbliżona do rzeczywistej obsługi systemu i przepływu procesów biznesowych w realnych warunkach. Tego rodzaju testy pomagają w weryfikacji aplikacji w ujęciu całościo­ wym, tj. „uczciwej” obsługi biznesu. Wyszczególnienie przypadków użycia daje pogląd, „jak” dana aplikacja będzie używana, z jakimi typowymi ścieżkami będzie musiała się zmagać w sposób ciągły.

136

Testowanie oprogramowania. Podręcznik dla początkujących

4.2. Projektowanie testu w oparciu o technikę białej skrzynki Testowanie instrukcji kodu polega na uruchomieniu każdej instrukcji przynajmniej raz. Pokrycie instrukcji kodu odnosi się do procentu uruchomionych instrukcji w wyniku wykonania przypadków testowych. Instrukcja to najmniejszy samodzielny fragment kodu, który jest wykonywalny. Listing 4.1. Przykład nr 1 do analizy pokrycia instrukcji kodu package p l . t e s t o w a n i e ; p u b l i c c l a s s TBookKod { p u b l i c s t a t i c v oi d m a i n ( S t r i n g a r g s [ ] ) i n t a = 1; i n t b = 0; i n t zc; i f (a > b) { zc = 100; } else { zc = 200;

{

} i f (a == 1) { zc = 300; }

Przypadek testowy dla powyższego programu (listing 4.1), w którym parametry a oraz b zainicjowane są wartościami odpowiednio 1 i 0, nie gwarantuje pełnego pokrycia in­ strukcji. Wskazane wartości wejściowe pokryją 4 z 6 instrukcji (linii kodu). Rysunek 4.4 prezentuje wynik wykonania instrukcji z omawianego listingu. Porównanie zapisu instrukcji z rezultatem uwiarygodni wywód, które linie programu zostały wykonane (pokryte). W celu zapewnienia 100% pokrycia testy należy uzupełnić o dodatkowy przypadek, który uruchomi blok el se pierwszej instrukcji warunkowej if. W tym celu można zainicjować program z wartościami a=2, b=5. Analizę pokrycia instrukcji oprzyjmy na jeszcze jednym przykładzie. Przyjrzyjmy się pseudoinstrukcjom na listingu 4.2. Uruchomienie bloku instrukcji z parametrem a=10 spowoduje wykonanie 80% instrukcji programu. Drugie uruchomienie z wartością a=1 pokryje pozostałe instrukcje.

Rozdział 4. ♦ Wprowadzenie do projektowania testów

137

Rysunek 4.4. Źródło programu wraz z rezultatem działania przy zadanych wartościach a = 1, b = 0 Listing 4.2. Przykład nr 2 do analizy pokrycia instrukcji kodu package p l . t e s t o w a n i e ; p u b l i c c l a s s TBookKod2 { p u b l i c s t a t i c v oi d m a i n ( S t r i n g a r g s [ ] ) i n t a = 10; i n t zc; i n t xc; i n t vc; S t r i n g wynik = "Wynik t o : ";

{

i f (a == 1) { zc = 100; } else { a = a * 5; zc = 200; xc = 500; vc = a - zc; vc = vc + xc; wynik = wynik + I n t e g e r . t o S t r i n g ( v c ) ; System.out.print(wynik); }

138

Testowanie oprogramowania. Podręcznik dla początkujących

Testowanie decyzyjne polega na weryfikacji zachowania aplikacji w momencie osiągnięcia punktu decyzyjnego w kodzie. Decyzja to miejsce w kodzie, które wpły­ wa na sterowanie, tzn. posiada co najmniej dwie alternatywne drogi, których wybór uzależniony jest od wartości parametrów wejściowych. Warunki logiczne mogą mieć charakter złożony, to znaczy taki, w którym występują więcej niż dwie ścieżki prze­ biegu. Pojedynczy warunek musi być przetestowany dwa razy. Raz „na praw dę ’, drugi raz „nafa łsz ”. Pokrycie w 100% decyzji zapewnia pełne pokrycie instrukcji kodu. Listing 4.3 zawiera przykładowy kod do analizy pokrycia decyzji. W celu pełnego pokrycia decyzji przy minimalnej ilości przypadków można zastosować rozwiązanie, gdzie a=100 i b=40, plus drugie wywołanie a=1 i b=30. Oba przypadki zagwarantują 100% pokrycia decyzji. Pierwszy z nich wymusi fałsz/praw da , a drugi prawda/fałsz . Listing 4.3. Przykład nr 1 do analizy pokrycia decyzyjności package p l . t e s t o w a n i e ; p u b l i c c l a s s TBookKod3 { p u b l i c s t a t i c v oi d m a i n ( S t r i n g a r g s [ ] ) i n t a = 100; i n t b = 40; i n t zc; S t r i n g wynik = "Wynik t o : ";

{

i f (a == 1) { zc = 100; wynik = wynik + I n t e g e r . t o S t r i n g ( z c ) ; System.out.print(wynik); } i f (a - b > 1) { zc = 200; wynik = wynik + I n t e g e r . t o S t r i n g ( z c ) ; System.out.print(wynik); } } }

Przypadki testowe realizowane w ramach testów pokrycia (ang. coverage test) mo­ delowane mogą być w oparciu o grafy przepływu sterowania (ang. Control Flow Graph — CFG). Graf (ang. graph) to graficzna reprezentacja relacji zachodzących po­ między poszczególnymi elementami programu. Listing 4.4 przedstawia źródło programu, które zostało odwzorowane na grafie z rysunku 4.5. Listing 4.4. Kod programu, który posłuży do przygotowania grafu przepływu sterowania package p l . t e s t o w a n i e ; p u b l i c c l a s s TBookGraph { / / Start p u b l i c s t a t i c v oi d m a i n ( S t r i n g a r g s [ ] ) / / K ro k 1 i n t a = 12; i n t zc; / / K ro k 2 i f (a >= 100) { zc = -5;

{

Rozdział 4. ♦ Wprowadzenie do projektowania testów

/ / K ro k 3 } else { / / K ro k 4 s wi t c h (a) { c a s e 0: zc = 0; b r e a k; c a s e 1: zc = 1; b r e a k; default: zc = 5; } } / / K ro k 5 System.out.print(zc); } } / / Koniec

Rysunek 4.5. Grafprzepływu sterowania przygotowany w oparciu o listing 4.4

139

140

Testowanie oprogramowania. Podręcznik dla początkujących

4.3. Projektowanie testu w oparciu o doświadczenie testera Brak lub niekompletność dokumentacji stosunkowo często doskwiera testerowi w mo­ mencie projektowania testów. Zbudowanie zestawu przypadków testowych oparte jest na informacjach uzyskanych z nieformalnych rozmów z programistami, analitykami i projektantami funkcjonalności. Nieformalnie zdobyta podstawa merytoryczna zwykle jest uzupełniana o informacje z dotychczasowej dokumentacji (może być nieaktualna) i/lub szczątkowy materiał analityczno-projektowy. Niemniej jednak wiodącym elemen­ tem jest podpieranie się doświadczeniem i intuicją testera. Testy zaprojektowane według tej metody w momencie ich zastosowania mogą nie w pełni odpowiadać rzeczywistym potrzebom. Oznacza to, że mogą one pomijać pewne obszary, które zostały dodane w momencie implementacji, a w czasie „wywiadu” nie były poruszone. Kolejnym problemem mogą się okazać różnice pomiędzy zapisami testu a faktyczną funkcjonalnością, np. programista wykonał implementację inaczej, niż zapowiadał. Dużym problemem jest swoboda w interpretacji założeń i brak for­ malnego powiązania (odpowiedzialności) na linii programista - tester. Ostateczna efektywność testów zaprojektowanych tą metodą może być niezadowalająca. Nieformalne projektowanie testów może posłużyć do szacunkowego określenia kosztu realizacji testów. Niemniej jednak należy pamiętać o ryzyku, jakie niesie ta metoda. Wartością dodaną metody eksploracyjnej jest możliwość poddania aplikacji testom przez osoby, które wcześniej nie miały styczności z systemem i uprzednio nie zapo­ znały się z dokumentacją. Nieporadna obsługa aplikacji może ujawnić problemy, które nie byłyby możliwe do wykrycia przez osoby mające „poukładaną” sekwencję zdarzeń. Niestety działa to również w drugą stronę. Testy poprzez „atak” na program z dużym prawdopodobieństwem nie pokryją w pełni wszystkich funkcjonalności. W rzeczywi­ stości tester projektuje i wykonuje przypadek w czasie rzeczywistym. Otwiera pewną funkcjonalność i stara się jej użyć zgodnie z tym, co podpowiada mu doświadczenie i intuicja. Metoda eksploracji systemu może posłużyć do odtworzenia dokumentacji, np. opisu GUI.

4.4. Przypadki testowe w ujęciu praktycznym Niestety nie istnieje złoty środek, za pomocą którego można szybko i obszernie opa­ nować sztukę projektowania przypadków testowych. Oczywiście punktem wyjścia jest opanowanie elementarnych podstaw teoretycznych, które stanowią podbudowę do planowania testów. W praktyce najdoskonalsze efekty uzyskuje się poprzez zastoso­ wanie wypadkowej wynikającej z doświadczenia, teorii, znajomości użytej technologii oraz intuicji. Chcę powiedzieć przez to, że tester, a zatem i opracowane przez niego

Rozdział 4. ♦ Wprowadzenie do projektowania testów

141

przypadki testowe rozwijają się i dojrzewają wraz z systemem. Czytelnicy, którzy li­ czyli, że w tej publikacji zaznajomią się ze sztuką projektowania uniwersalnych przy­ padków testowych, mogą czuć się w pewnej mierze nieusatysfakcjonowani. Moim celem jest wskazanie, jak ważne jest poprawne zaprojektowanie przypadku testowego 1 jakie konsekwencje wiążą się z błędnie przygotowanym planem testów. Zrozumie­ nie wagi problemu stanowi istotę zagadnienia. Zwykle początkujący tester lub tester rozpoczynający pracę z zupełnie nowym systemem korzysta z przypadków testo­ wych wykonanych przez osobę bardziej znającą system. Taka kolej rzeczy umożliwia stosunkowo płynne nauczenie się nowej aplikacji (testować zapewne już umiemy). Je­ żeli potrafimy testować i znamy system, to z pewnością zostaniemy poproszeni również o projektowanie testów w niedalekiej przyszłości. Poniżej przytoczę kilka przykładów (sytuacji), które z pewnością naświetlą powagę problemu i uwiarygodnią mój wywód.

Przykład 1. Błędnie zaprojektowany przypadek dla operacji iloczynu Rozdział rozpocząłem od podania w wątpliwość poprawności testu dla jednej z operacji kalkulatora matematycznego. Precyzując: chodzi o operację iloczynu. Jest to przykład często przytaczany w literaturze. Wynika to z tego, że bardzo precyzyjnie i jednoznacz­ nie uwypukla sedno problemu. Najprostszy przypadek weryfikacji operacji mnożenia powinien uwzględniać dwie liczby całkowite, które będą stanowiły wartości wejściowe. W sytuacji kiedy podamy je odpowiednio 2 i 2, czyli założymy wykonanie operacji 2 * 2 i za spodziewany wynik uznamy liczbę 4, ten test nie może być uznany za pra­ widłowy. Dlaczego? Otóż ten sam wynik może (powinna) zwrócić operacja sumowa­ nia, tj. 2 + 2 = 4. Jeżeli system zwróci 4, to pomimo że zaznaczyliśmy (wybraliśmy) opcję mnożenia, nigdy nie mamy pewności, czy instrukcje programu napisane są prawidłowo. Przyjrzyjmy się listingowi 4.5, który prezentuje kod źródłowy hipote­ tycznego kalkulatora wykonanego w technologii REST. Listing 4.5. Kod źródłowy kalkulatora (z błędem w operacji mnożenia) package k a l k u l a t o r _ r e s t ; i mport j a v a x . ws . r s . G E T ; i mport j a v a x . w s . r s . P a t h ; i mport j a v a x . w s . r s . P a t h P a r a m ; @P a t h ( " / p o l i c z " ) public cl as s Kalkulator { S t r i n g wynik="Wynik o p e r a c j i dodawani a (suma) t o : "; S t r i n g wynik2="Wynik o p e r a c j i mnożeni a ( i l o c z y n ) t o : "; @GET @Path("{x}+{y}") p u b l i c S t r i n g dodawani e( @PathParam("x") i n t arg1, @PathParam("y") int arg2){ i n t w=arg1+ ar g2 ; wyni k = w y n i k + I n t e g e r . t o S t r i n g ( w ) ; r e t u r n wynik; } @GET @Pat h("{x}- {y}")

142

Testowanie oprogramowania. Podręcznik dla początkujących

p u b l i c i n t odej mowani e( @PathParam("x") int argl, @PathParam("y") int arg2){ r e t u r n ar g1 -a rg 2; } @GET @Pat h("{x}*{y}") p u b l i c S t r i n g mnożeni e ( @PathParam("x") int argl, @PathParam("y") int arg2){ / / B łą d w kodzie dla operacji iloczynu / / Prawdopodobnie w w yniku kopiowania kodu z metody dodawanie i n t w=arg1+arg2; wyni k 2 = wy n i k 2 + I n t e g e r . t o S t r i n g ( w ) ; r e t u r n wynik2; } @GET @Pat h("{x}/ {y}") public i n t dzi el en ie( @PathParam("x") int argl, @PathParam("y") int arg2){ r etu rn arg1/arg2; } }

Metoda mnożenie zawiera błąd. Pomimo wskazania, że intencją użytkownika jest wy­ konanie iloczynu, realizuje ona operację dodawania (rysunek 4.6). Tak prosty błąd mógł powstać np. poprzez kopiowanie kodu przez programistę, który zmienił wywo­ łanie URL (@Path("{x}*{y}")dla metody, ale zapomniał zmodyfikować implementację logiki (int w=arg1+arg2;). Wracając do pierwotnie założonego testu 2 * 2 = 4, przyj­ rzyjmy się dwóm kolejnym rysunkom: 4.7 oraz 4.8. Wykonaliśmy operacje odpo­ wiednio sumowania i mnożenia. Oba rezultaty realizacji żądania to 4 na skutek podania parametrów wejściowych 2 i 2 . Nie wiemy, czy pod wywołaniem operacji sumowania kryje się faktycznie dodawanie i na odwrót (pomijając pomocniczą etykietę, którą również zwraca WS). Rysunek 4.6. Kalkulator — operacja mnożenia z błędem

Rysunek 4.7. Kalkulator — operacja dodawania

■ f i f i S B H I C h ttp ://127.0.0.1:808...latorREST/policz/2+2 [ + [ f

Ą

127.0.0.1:8080.-T B cckK a lku la tG rR E S T /p o lkz/2 + 2

Wynik operacji dodawania (suma) to: 4

Rozdział 4. ♦ Wprowadzenie do projektowania testów

Rysunek 4.8.

143

http://1270.0.1:808.JatorREiT/policz/2*2 | +

Kalkulator — operacja mnożenia

^

®

127.0.0.18Ü80/T BcokKalkulatorRE ST/ po 11icz/2 *2

Wynik operacji mnożenia (iloczyn) to: 4

Niemniej jednak modyfikując wartości początkowe, na przykład wprowadzając 2 * 3 , z łatwością zweryfikujemy, czy operacja działa właściwie. Spodziewany wynik to 6, a funkcja zwraca 5 (rysunek 4.9). Zatem skuteczność testu zależy od prawidłowo za­ projektowanego przypadku testowego. Powyższa sentencja może stanowić mantrę dla każdego testera. Rysunek 4.9. Kalkulator — poprawne dane wejściowe (iloczyn)

• _ http://127.0.0.1;80S...latorREST/policz/2*3 4 1

L*J

127.0,0.1:8080.'TBoclcKalkulatorREST •pclicz./j'J

Wynik operacji mnożenia (iloczyn) to: 5

Przykład 2. Błąd w kalkulatorze dopuszczonym do sprzedaży — kupiłem i wykryłem Pozostając w tematyce kalkulatorów, przytoczę przykład (błąd), jaki zauważyłem we własnym urządzeniu. Rozpakowałem „sprzęt” nabyty za kilkanaście złotych i przy­ stąpiłem do badania jego możliwości. Nie spodziewałem się niczego nadzwyczajnego po tym sprzęcie, ale także nie podejrzewałem, że będzie zawierał tak „głupi” błąd. Zdawało mi się, że układy elektroniczne do liczydeł są tak powszechne, że rzeczą naturalną jest ich poprawne działanie. A tu taka niespodzianka. Mój kalkulator po­ zwala na wprowadzanie ciągu, tj. liczby z wieloma kropkami, np. 40.0.0... 0. Nietrud­ no się domyślić, że wszelkie obliczenia kończą się wyjątkiem (błędem). Irytuje mnie to niezmiernie, gdyż za każdym razem w wyniku mojej nieuwagi tracę całe obliczenie. Kara jest niewspółmierna do winy, niestety. W tak prostych urządzeniach — tzn. pod względem interfejsu i interakcji z użytkownikiem — można było się pokusić o wyłącze­ nie wstawiania drugiej kropki w podstawowym trybie obliczeń. Powyższy przykład uwiarygodnia tezę, że błędy mogą wystąpić zawsze.

Przykład 3. Testy zachowania aplikacji w momencie utraty kooperacji z innym systemem Systemy, które wymagają współpracy z innymi aplikacjami, powinny być poddane we­ ryfikacji pod kątem ich zachowania w momencie utraty „kontaktu” ze zdalnym obiek­ tem. Wspomniana utrata łączności może nastąpić przed próbą użycia zdalnej funkcjonal­ ności. W takim przypadku zwykle użytkownik otrzymuje stosowny komunikat, np. funkcjonalność w chwili obecnej je s t niedostępna. Niestety dużo gorszą sytuacją jest przerwanie komunikacji w momencie realizacji procesu biznesowego, np. pobieramy dane z WS do wygenerowania jakiegoś raportu. Użytkownik wybrał opcję generuj raport . Aplikacja wysłała żądanie, odebrała odpowiedź i ponownie wysłała żądanie do innej funkcji WS. Niestety drugi krok nie mógł zostać zrealizowany ze względu na

14 4

Testowanie oprogramowania. Podręcznik dla początkujących

przerwaną komunikację ze zdalną usługą sieciową. Pytanie, jak zachowa się aplikacja w takich okolicznościach? Trzeba to sprawdzić i spreparować podobny scenariusz.

Przykład 4. Walidacja dopuszczalnych znaków w polu formularza Formularze zwykle posiadają stosunkowo silną walidację wprowadzanych danych, tj. wykluczają pewne znaki ze względów bezpieczeństwa i na potrzeby zachowania spójności z innymi systemami etc. Zatem konieczność weryfikacji tego rozwiązania staje się nieunikniona. Załóżmy, że w specyfikacji podano, że pole numer telefonu nie dopuszcza następujących znaków: < > ’l~{}{}?/;\. Czy test, w którym wprowadzimy od razu cały wykluczany ciąg, będzie poprawny (rysunek 4.10)? Nie wydaje mi się z dwóch powodów. Po pierwsze: w ten sposób nie dowiemy się, jak aplikacja reaguje na poprawne dane, tzn. czy potrafi prawidłowo przeszukać cały ciąg w poszukiwaniu zakazanych znaków. Po drugie: nie możemy mieć pewności, czy oprogramowanie wyłapuje wszystkie znaki. Jeżeli nie mamy wglądu w kod źródłowy, a komunikat walidacyjny jest niezwykle lakoniczny, np. wprowadzono niepoprawne znaki/dane, to skąd wiemy, czy walidacja zadziała tak samo dla każdego ze znaków — zakładam, że po wykryciu pierwszego następuje przerwanie weryfikacji i zwrot komunikatu walidacyjnego. Nieco bardziej kulturalnym i cywilizowanym rozwiązaniem jest wypisanie w „zwrocie”, jakie zabronione znaki wykryto. W takim przypadku podanie od razu pełnego wykluczanego ciągu nabiera większego sensu. Weryfikacja wspomnianego wymagania powinna uwzględniać przypadki z ciągiem znaków mieszanych (błędne i poprawne), tylko błędne, tylko poprawne oraz jeżeli jest to wymagane — jednostkowe (pojedyncze) testy dla każdego z zabronionych znaków. Rysunek 4.10. Test walidacji wprowadzanych danych — ryzykownie zaprojektowany

Edycja zlecenia doładowania W yb ie rz rachunek obciążany Podaj nr telefonu:

102030405000009 l< > rm } ? /;\

Podaj kwotę doładowania: W y b ie rz a k c jf

PLN

Anuluj | | Czyść | | Zatwierdź [

Niestety formularze nie ograniczają się do jednego pola, a i system zwykle posiada ich wiele dla różnych procesów biznesowych. Sytuacja jest o tyle ciekawa, że często reguły walidacyjne są propagowane na inne analogiczne pola. Jeżeli czujemy się na siłach, możemy podjąć próbę oceny, czy owe walidacje realizowane są w oparciu o jedną i tę samą metodę (fragment kodu). Możemy również zaufać informacjom płynącym od programisty. Niemniej jednak jeżeli nabierzemy wystarczającego zaufania do silnika tych reguł, to testując kolejne pola, możemy złagodzić rygor testowy.

Przykład 5. System rezerwacji imprezy turystycznej online Jednym z poważniejszych błędów w systemie produkcyjnym, który udało mi się wy­ kryć jako użytkownik, była wada systemu rezerwacji imprezy turystycznej. Problem dotyczył obliczania kosztów wycieczki przy uwzględnieniu wieku dziecka. Załóżmy, że za dziecko do lat dwóch (w momencie powrotu) wnosi się jedynie opłatę za ubez­ pieczenie. Powyżej tego wieku koszty znacznie wzrastają.

Rozdział 4. ♦ Wprowadzenie do projektowania testów

145

Kalkulowałem koszty dla dwóch osób dorosłych i dziecka (2+1), które w momencie powrotu miałoby 2 lata i 6 miesięcy. System po podaniu daty urodzenia dziecka nie wiadomo czemu klasyfikował je w przedziale k/W £T estBt>ok?w sdl [ + ♦

*

©

5

; 127,0.0.1 :S 0 8 0/W S T B o ok /W S T e s tB o ok ? w s dl

Podany plik XML nie zawiera żadnych informacji o stylach z nim związanych. Poniżej wyświetlone jest drzewro dokumentu.



— re tu rn N a m e

©

to llp p e rC a s e

M o ckS e rvice P ro pe rtie s

to U pp erC a se

| C u s to m P roperties

P ro p e rty Nam e

h e llo

V alue W S T e stB o okP o rtB ind in ... Descri...

D e scrip tio n Path

/m o c k W S T e s tB o o k P o rt..

P ort

8088

M a tc h SOAP V ersion

false

R equire SOAP A c tio n

false

D isp a tch Responses

false

0

P rop...

S ta rt...

S top ...

O nR eques...

A fte rR e q ue ...

Enable □

In c o m in g WSS D e fa u lt O u tg o in g WSS

M essage Log

Rysunek 7.17. SoapUI — sterowanie pracą symulatora Zbudowany MockService udostępniony jest pod adresem http://127.0.0.1:8088/mockWS TestBookPortBinding. Standardowo po dopisaniu do adresu URL ciągu ?WSDL w prze­ glądarce można sprawdzić, czy serwer „żyje”. Dobrze, otwórzmy ponownie SoapUI i stwórzmy nowy projekt przy wykorzystaniu naszego MockService (rysunek 7.18). Po zatwierdzeniu zostanie wygenerowany dobrze już nam znany projekt. Dysponujemy skonfigurowaną tylko jedną funkcją w symulatorze, zatem skupimy się na w yw oły­ waniu właśnie jej. Przypomnę, iż MOCK będzie zwracał sekwencyjnie przygotowane odpowiedzi (rysunek 7.15). Zatem spodziewamy się, iż trzy kolejne wywołania w odpo­ wiedzi dostaną kolejno Response 1, Response 2, Response 3, a czwarte żądanie otrzyma

Response 1.

176

Testowanie oprogramowania. Podręcznik dla początkujących

Rysunek 7.18. SoapUI — klient MockService

V

N e w SOAP P ro ject

New SOAP Project Creates a WSDL/SOAP based P ro ject in th is w o rksp ace

P ro je ct N am e:

| K lie n t M ockS ervice __________________________________________________

In itia l WSDL:

| http://127.Q .Q .l:8 Q 8 8 /m ockW S T e stB oo kP o rtB in din g ?w sd^

Create Requests: 0

| [ B ro w

Create sa m p le requests f o r all o perations?

C reate TestSuite: O Creates a T e s tS u ite fo rth e im p o rte d WSDL R elative Paths:

Q

Stores all file path s in p ro je c t re la tive ly to p ro je c t file (requires save) OK

Rysunek 7.19 przedstawia pierwsze wywołanie testowanej funkcji MockService. Zgodnie z założeniem symulator odpowiedział pierwszym obiektem odpowiedzi. Anali­ zując treść komunikatu, bezsprzecznie można potwierdzić realizację planu odpowie­ dzi. Zachowanie samego symulatora można śledzić bezpośrednio w SoapUI, w oknie uruchamiania usługi. Rysunek 7.20 przedstawia cztery żądania do MockService oraz w oknie na pierwszym planie treść odpowiedzi dla trzeciego wywołania. Zatem z po­ wodzeniem od strony zarządzania symulatorem można weryfikować treść żądań oraz re­ alizowanych odpowiedzi. Reasumując, przygotowany MockService dla funkcji get ^LengthText pracuje zgodnie z zadanym algorytmem, tj. odsyła zdefiniowaną treść w oparciu o sekwencję zdarzeń.

Rysunek 7.19. SoapUI — pierwsze wywołanie funkcji MockService poprzez klienta

Rozdział 7. ♦ Testowanie usług sieciowych

177

Rysunek 7.20. SoapUIMockService — lista wywołań

7.3. Monitor TCP — Apache TCPMon Apache TCPMon to niezwykle proste i użyteczne narzędzie do monitorowania ruchu sieciowego poprzez TCP. Aplikację można pobrać ze strony domowej projektu:

http://ws. apache. org/tcpmon/index. html. Wspominałem na poprzednich kartach książki, iż zdarzają się sytuacje, kiedy tester chciałby (musi) podejrzeć dokładnie, jak wygląda komunikacja pomiędzy klientem a serwerem, np. w relacji klient - serwer usługi sieciowej. Załóżmy, iż weryfikujemy daną funkcjonalność aplikacji, która komunikuje się z zewnętrznym WS, do którego nie mamy dostępu. W istocie wszystko działa, aplikacja wysyła i pobiera dane (request, response). Niemniej jednak czasami dobrze jest „obejrzeć” sobie wymianę komuni­ katów, a w zasadzie ich treść w celu zweryfikowania poprawki lub odtworzenia błędu. Nie mniej istotną wartością jest zgłębianie tajników aplikacji poprzez rozgryzanie jej funkcjonalności od strony technologicznej (implementacji). Zastosowanie monitora TCP/IP umożliwi podgląd treści wymiany komunikatów pomiędzy serwerem a klientem.

178

Testowanie oprogramowania. Podręcznik dla początkujących

Apache TCPMon to bardzo łatwe i proste narzędzie. Oprócz monitorowania ruchu oferuje on możliwość uruchomienia proxy oraz wysyłania komunikatów SOAP do ser­ wera usług sieciowych (web services). Monitor TCP należy włączyć do infrastruktury pomiędzy linię komunikacji klient serwer (rysunek 7.21).

Rysunek 7.21. Implementacja monitora TCP w infrastrukturę

Rysunek 7.22 prezentuje główną kartę TCPMon, na której konfigurujemy parametry nasłuchu. W polu Listen Port # wskazujemy, na którym porcie (lokalnie) ma nasłu­ chiwać monitor. W kolejnym polu Target Hostname definiujemy, dla którego hosta ma być podglądana transmisja. Analogicznie postępujemy z polem Target Port # , okre­ ślając port na serwerze, na który ma być przesłane żądanie. W przypadku zilustrowanym na poniższym rysunku 7.22 wywołanie 127.0.0.1:8888 „obudzi” monitor, który prześle wiadomość na adres 127.0.0.1:8080. Przepływ komunikacji przez monitor TCP po­ zwoli na monitoring treści komunikatów. Załóżmy, iż web service jest „wystawiony” pod adresem 127.0.0.1:8080. Chcemy włączyć nasłuch komunikacji. Definiujemy mo­ nitor TCP, który będzie oczekiwał na ruch pod adresem 127.0.0.1:8888. Teraz należy przekonfigurować klienta WS, tak aby zamiast docelowego adresu serwera usług sie­ ciowych wywoływał adres monitora TCP, który po odczytaniu treści komunikatu skieruje go do docelowej lokalizacji. Oczywiście serwer odpowie do monitora TCP, który przekaże wiadomość do naszego klienta. W taki oto sposób uzyskamy wgląd w treść komunikacji, o ile nie jest ona szyfrowana, gdyż TCPMon nie wspiera SSL.

Rysunek 7.22. TCPMon

— konfiguracja nasłuchu

Rozdział 7. ♦ Testowanie usług sieciowych

179

Przyciskiem Add na stronie głównej TCPMon dodajemy uprzednio zdefiniowaną kon­ figurację nasłuchu. Na karcie wskazanego portu (rysunek 7.23) mamy możliwość za­ trzymania nasłuchu oraz podglądu treści request i response. W sytuacji kiedy chcieli­ byśmy udokumentować test lub uzyskać łatwo edytowalny zapis treści komunikacji, można za pomocą opcji Save zapisać wynik do pliku.

Rysunek 7.23. TCPMon — podgląd komunikacji Rysunek 7.24 prezentuje wywołanie funkcji usługi sieciowej poprzez pośrednika ( 127.0.0.1), tj. monitor TCP. Serwer usług sieciowych uruchomiony jest pod adresem 127.0.0.1:8080. Na rysunku 7.23 widać podgląd treści komunikacji, jaka zaszła pomię­ dzy klientem (SoapUI) a usługą sieciową.

Rysunek 7.24. Wywołanie poprzez SoapUI monitora TCP

180

Wskazówka

Testowanie oprogramowania. Podręcznik dla początkujących

P o s łu g iw a n ie s ię n a rz ę d z ia m i typ u p ro xy lub TCP m o n ito r w y m a g a z n a jo m o ś c i p o d s ta w z a d re s o w a n ia IP . A d re s IP je s t logicznym id e n ty fik a to re m in te rfe js u s ie ­ cio w e g o (k a rty s ie c io w e j). P o rt słu ży d o id e n ty fik o w a n ia z d a ln ie fu n k c jo n u ją c y c h u s łu g (p ro c e só w ) i re p re z e n to w a n y je s t przez liczby n a tu ra ln e od 0 do 6 5 5 3 5 . P o rty od 0 do 1 0 2 3 s ą trw a le za re ze rw o w a n e na tzw . o g ó ln ie p rzyp isa n e u s łu g i, tj. WWW, SMTP, POP3, FTP (ang. well known ports). S ta n d a rd o w e przypisania (rezerwa­ cję) m ożna spraw dzić na stro n ie organizacji IANA (http://w w w .iana.org/assignm ents/ service-names-port-numbers/service-names-port-numbers.xhtml). Gn ia z d o (an g . socket) to p o łą c z e n ie a d re s u IP o ra z p o rtu , n p . 127 .0 .0 .1 :8 0 8 0 . D zięki z a s to s o ­ w aniu g n ia z d a m ożn a za p o m o c ą je d n e g o in te rfe js u s ie c io w e g o u ru c h a m ia ć różne u s łu g i, np. 1 2 7 .0 .0 .1 :8 0 8 0 (WWW) o ra z 1 2 7 .0 .0 .1 :2 1 (FTP).

TCPMon można zintegrować bezpośrednio z narzędziem SoapUI. W tym celu należy wywołać ustawienia globalne SoapUI oraz na zakładce Tools wskazać miejsce rezy­ dowania TCPMon (rysunek 7.25). W menu kontekstowym interfejsu (rysunek 7.26) można połączyć się z monitorem TCP poprzez opcję Launch TcpMon. W kolejnym kroku (rysunek 7.27) trzeba wskazać endpoint oraz port. Zatwierdzenie (Launch) otworzy okno z narzędziem TCPMon.

Rysunek 7.25. SoapUI — konfiguracja TCPMon

Rozdział 7. ♦ Testowanie usług sieciowych

Rysunek 7.26.

B

SoapUI — łączenie się z TCPMon, krok nr 1

181

i ) MOC WSTestBook

I WSTestBoo

-

i

Show Interface Viewer

£■ getForL getLeng

E n te r

ro

Add JMS endpoint

-Q

è

'i

getSum

% ü

getSysd

+

i-

hello

Check WSI Compliance

Î

2

returnN

Launch TcpMon

i

Ü toUppei

0 ' '■* getForL

i

j. getLeng

i

ÿ getSum

Rysunek 7.27. SoapUI — łączenie się z TCPMon, krok nr 2

^

Generate Documentation

i

5 getSysd ED Update Definition

i

ÿ hello

i i

C tr l+ A lt- W

Generate TestSuite i | Launch Tcp Mon for Generate MockService

I WSTestBoo

-



Generate Code

F.5

^1=] Export Definition

C trl-P

J. returnN J. toUppei

Clone Interface

F9

Remove

D ele te

Online Help

FI

g i

Launch T cp M o n

Launch T cp M o n

B

S p e c ify a r g u m e n ts f o r la u n c h in g T c p M o n

E n d p o in t: Local P o ±

h t t p : / / 1 2 7 ,0 .0 .1 :8 0 8 0 /W S T B o o k /W S T e s tB o o lc

A d d lo c a l e n d p o i n t O

m

h

j8 0 8 3 a d d s a n e n d p o in t t o t h e i n te r fa c e p o i n t i n g t o t h e s ta rte d m o n it o r

1Launch |

f C lo s e | f T o o ls

]

TCPMon to proste i przejrzyste narzędzie. Niestety nie wspiera SSL. Niniejsza pu­ blikacja wzbogacona jest o dodatki B i C, w których przytoczone są dodatkowe dwa na­ rzędzia (monitory). Treść wspomnianych dodatków pozwoli na wstępne zapoznanie się z bardziej rozbudowanym oprogramowaniem wspomagaj ącym testy.

Rozdział 8.

Wprowadzenie do automatyzacji testów Automatyzacja testów może rozwiązać część problemów związanych z testowaniem oprogramowania. Jednakże nie może być ona traktowana jako panaceum na wszelkie trudności i niedogodności procesu weryfikacji jakości systemu. Zbyt wygórowane oczekiwania w kwestii spodziewanych wyników mogą okazać się zgubne w skutkach. W skrajnych przypadkach źle przygotowane wdrożenie automatyzacji może nie przy­ nieść oczekiwanych rezultatów, a wręcz zakończyć się całkowitym niepowodzeniem. Daleko idącym skutkiem ubocznym procesu wdrażania automatyzacji może okazać się osłabienie potencjału testów manualnych. Wypadkowa korzyści i strat nie zawsze będzie in plus. Poważnym zagrożeniem jest zmniejszenie zaangażowania zasobów w testy manualne przy jednocześnie kulejących testach automatycznych. W ujęciu cało­ ściowym ogólna jakość oprogramowania ulegnie obniżeniu. Rozważania na temat wprowadzenia automatyzacji testów należy rozpocząć od od­ powiedzi na kilka kluczowych pytań:

Co chcemy osiągnąć? Jaki je st cel automatyzacji? Czy nasza aplikacja nadaje się do automatyzacji? Czy mamy zasoby, aby takie testy prowadzić? Zasadniczym celem automatyzacji testów jest ograniczenie nakładów finansowych na realizację powtarzalnych i stałych testów. Ów cel realizuje się poprzez zastąpienie eg­ zekucji zadań wykonywanych manualnie przez automatyczny skrypt testowy. Prawi­ dłowo wdrożona automatyzacja przejmie zadania części osób, które mogą być skierowa­ ne do innych zadań. Jednocześnie należy zauważyć, że testy automatyczne wymagają oddelegowania przynajmniej jednej osoby, która będzie rozwijać, pielęgnować i wyko­ nywać skrypty. Bilans kosztów i zysku wdrożenia oraz utrzymywania testów auto­ matycznych musi być dodatni. W przypadku wątpliwości co do wykonalności tego założenia należy odstąpić od wcielania opisywanego planu w życie.

18 4

Testowanie oprogramowania. Podręcznik dla początkujących

Dwa obszary testów, które warto brać pod rozwagę pod względem automatyzacji, to te­ sty wydajnościowe i regresywne. Dlaczego? Powtarzalny zestaw przypadków testowych idealnie nadaje się do powierzenia ich realizacji automatowi. Taki warunek jest moż­ liwy do uzyskania właśnie przy testach regresywnych i obciążeniowych. Automaty są bardzo czułe na duże zmiany interfejsu użytkownika. Z tego powodu nie wszystkie obszary aplikacji mogą kwalifikować się do tego rodzaju testów. Automatyzowany obszar powinien być stabilny, kompletny, mało podatny na zmiany GUI oraz gwarantu­ jący powtarzalność wykonywanych testów. Testy automatyczne nie oznaczają, że realizowane są one bezobsługowo. Wymagają opiekuna, który będzie projektował, utrzymywał i wykonywał skrypty testowe. Osoba oddelegowana do tych prac musi posiadać odpowiednie predyspozycje i kom­ petencje. Drugą kwestią jest ocena zasobów, tj. oprogramowania i infrastruktury. Au­ tomatyzacja oparta jest na specjalistycznym oprogramowaniu narzędziowym, a same skrypty testowe i wyniki testów muszą być magazynowane i archiwizowane. Co warto automatyzować? Testy automatyczne doskonale sprawdzają się przy rela­ tywnie prostych interfejsach użytkownika i bardzo rozbudowanej logice biznesowej. Doskonałym przykładem są aplikacje wyliczające stawki ubezpieczenia, gdzie ilość parametrów wejściowych nie jest zatrważająca, natomiast ostateczny wynik zależy od pokaźnej pracy logiki systemu. Automat idealnie będzie nadawał się do wykonania 100, 200 różnych przypadków testowych, które będą „męczyć” ten sam obszar logiki w kodzie przy jednoczesnym podstawianiu szerokiego spektrum danych. Testy manu­ alne byłyby męczące dla osoby, która musiałaby kilkadziesiąt razy obsłużyć tę samą formatkę. Faktem oczywistym jest zysk na czasie egzekucji takich testów. Maszyna wykona je znacznie szybciej z jednakową precyzją przy każdym wywołaniu zestawu testów. Równolegle tester może weryfikować system poprzez dużo bardziej wyrafino­ wane, skomplikowane i nieszablonowe przypadki. Zakładając, że w omawianym przy­ padku zmodyfikowano logikę pod względem optymalizacji i wydajności, wspomnia­ ne testy doskonale sprawdzą się jako regres funkcjonalności, tzn. maj ą potwierdzić, że biznes realizowany jest zgodnie z oczekiwaniem (bez zmian). Obszary aplikacji, które z dużym prawdopodobieństwem będą często modyfikowane (GUI), należy pominąć, gdyż dostosowywanie skryptów automatycznych do nowego stanu może okazać się zbyt kosztowne. Pewne odstępstwa od tej reguły powinny mieć podłoże w dużym po­ ziomie ryzyka związanego z daną funkcjonalnością. Obszary strategiczne pomimo dużego kosztu utrzymywania testów automatycznych mogą być poddawane takiej w e­ ryfikacji ze względu na konieczność dużej precyzji i powtarzalności czynności, tzn. automat wykona takie testy staranniej niż człowiek. Automatyzacja testów przydaje się niezmiernie również przy testach wydajnościo­ wych. Za pomocą automatu można symulować obciążenie aplikacji przez wskazaną liczbę użytkowników, np. 5000. Trudno wyobrazić sobie zaangażowanie tak dużej liczby testerów w celu obsługi testu. Obciążanie systemu dużą liczbą użytkowników to nie jedyna wartość, można to robić długotrwale przy jednoczesnym modelowaniu przepływu obciążenia. Skrypt automatyczny może być wykonywany przez 2 - 3 go­ dziny, ale obciążenie (liczbą użytkowników, przez zaangażowane obszary) nie musi być stałe. Możemy w sposób niejednostajny i różny pod względem logiki obciążać system. Bardzo dobrze do tego celu nadaje się narzędzie Apache JMeter. Skrypty te­ stowe również bardzo dobrze sprawdzają się podczas zasilania systemu (bazy danych)

Rozdział 8. ♦ Wprowadzenie do automatyzacji testów

185

zestawem danych testowych. Bywają testy, których warunkiem początkowym jest wolumen kilku tysięcy różnorodnych wierszy w tabeli (tabelach). Przygotowanie ręczne takiego zestawu danych zajęłoby niewyobrażalnie dużo czasu. W praktyce automatyczne zasilanie danymi może okazać się przydatne w trakcie konfiguracji i uru­ chamiania środowiska szkoleniowego (np. realizacji kursu dla użytkowników). Wspomniałem, że automatyzacja testów regresywnych poszczególnych funkcjonalności jest bardzo czuła na zmiany w GUI. Duża część narzędzi funkcjonuje w oparciu o „na­ grywanie” przykładowej obsługi, która później jest wielokrotnie odtwarzana. Oczywi­ ście tak nagrany skrypt można modyfikować np. poprzez podstawianie danych z gene­ ratora lub plików, jednak podstawowa ścieżka pozostaje bez zmian. Jeżeli zmieni się liczba pól na formularzu lub ulegnie zmianie wywołanie jakiejś funkcji, to taki skrypt musi być zmodyfikowany (dostosowany). Zatem bardzo ważne jest aktualizowanie zgromadzonych skryptów, tak aby cały czas spełniały swoją rolę. Osoba zajmująca się automatyzacją musi na bieżąco śledzić zmiany w systemie i reagować w czasie rze­ czywistym, tzn. dopasowywać zestaw skryptów do bieżącej sytuacji.

J a k wdrożyć automatyzację? Jeżeli już wiemy, co chcemy osiągnąć, mamy zdefiniowane obszary systemu do au­ tomatyzacji, należy zastanowić się nad wyborem narzędzia. Mamy do dyspozycji trzy podstawowe ścieżki. Wybieramy oprogramowanie typu open source, zdajemy się na narzędzia komercyjne lub piszemy własne aplikacje. Niewielkie programy własne­ go autorstwa nie powinny budzić kontrowersji. Bywają miejsca w systemie, które należy obsłużyć w autorski sposób, a częstotliwość odwołań właśnie do tej funkcjo­ nalności daje przesłanki do powołania dedykowanego narzędzia. Oprogramowanie darmowe stwarza duże możliwości i warto próbować wykorzystywać je do codzien­ nej pracy. Niemniej jednak nie jesteśmy chronieni w sytuacji, kiedy nagle organiza­ cja, która je wydała, przestaje je rozwijać. Nieco inaczej jest z oprogramowaniem komercyjnym, gdy wiąże nas umowa licencyjna (prawa i obowiązki obu stron). Bardzo niewskazany jest huraoptymizm i nagły zmasowany atak na automatyzację wszyst­ kiego. Dobrą praktyką jest przeprowadzenie pilotowego projektu, którzy „przetrze szlak” i zwróci pierwsze dane (efekty). Na podstawie zebranych danych z prototypo­ wego projektu będzie można podjąć decyzj ę o kontynuowaniu prac lub o zmianie po­ dejścia i narzędzia. Zanim zdecydujemy się na zakup narzędzia, musimy być pewni, że sprawdzi się ono w naszych warunkach. Zbyt pochopne działanie może obciążyć budżet, nie daj ąc w zamian żadnego zysku. Niestety wiele projektów automatyzacji kończy się porażkami, gdyż nie dopasowano dostatecznie możliwości narzędzia do po­ trzeb i technologii, w jakiej wykonana jest aplikacja. Krótkowzroczność jest także przyczyną porażki. To, że na chwilę obecną wybrane narzędzie sprawdza się dobrze, nie oznacza, że w niedalekiej przyszłości równie sprawnie będzie obsługiwać system po planowanych zmianach, np. wymianie/modyfikacji jakiegoś kluczowego komponentu. Wdrożenie automatyzacji nie może odbywać się pochopnie ani pod presją trendu. Nie wszystkie systemy nadają się do automatyzowania testów, niektóre są do tego stwo­ rzone, ale koszty wdrożenia automatyzacji przewyższają zyski, a jeszcze inne da się zautomatyzować tylko fragmentarycznie.

186

Testowanie oprogramowania. Podręcznik dla początkujących

Przykładowe narzędzia automatyzacji testów: ♦ Selenium — http://www.seleniumhq.org/.

♦ Apache JMeter — http://jmeter.apache.org/. ♦ Oracle OpenScript — http://www.oracle.com.

Dodatek A

Generowanie sumy kontrolnej Suma kontrolna (ang. checksum) to liczba wygenerowana na podstawie danych, których poprawność ma ona potwierdzić w przyszłości. Ów ciąg znaków generuje się na przy­ kład dla plików wymiany danych pomiędzy systemami. Plik z sumą kontrolną prze­ kazywany jest wraz ze zbiorem głównym danych. Aplikacja odbierająca (wczytująca) otrzymany plik źródłowy również generuje sumę kontrolną i porównuje ją z plikiem sumy otrzymanej z zewnętrznego systemu. Jeżeli obie sumy się zgadzają, to można przyjąć, że dane w trakcie przesyłania nie uległy uszkodzeniu. W przypadku wykrycia niegodności należy przyjąć, że dane uległy przekłamaniu. Specyficznym rodzajem sumy kontrolnej są liczby kontrolne na przykład w numerze PESEL lub NIP. Generowanie sumy kontrolnej nie jest procesem trudnym i skomplikowanym. Niemniej jednak w trakcie testów oprogramowania (pliki importu i eksportu danych) często za­ chodzi konieczność przygotowania jej, gdyż nie będziemy mogli uruchomić np. im­ portu danych kampanii marketingowej. Proces importu zwykle rozpoczyna się od po­ równania dostarczonego pliku sumy kontrolnej z sumą wygenerowaną w oparciu o plik importowany. W sytuacji kiedy aplikacja nie będzie mogła podjąć próby weryfikacji wspomnianych dwóch sum kontrolnych z uwagi na brak pliku pierwotnego, przerwie proces. W tym miejscu należy nadmienić, że pełne testy funkcjonalne często inicjowane są importem właściwych danych. Zatem weryfikacja wyświetlania kampanii marke­ tingowej będzie możliwa dopiero po prawidłowym imporcie danych do właściwych struktur w bazie. Często w specyfikacji plików wymiany danych zawarta jest informacja o znaku końca linii (ang. end o f line), np. LF lub CRLF. Załóżmy, że plik wymiany danych będzie kończył linię tekstu znakiem CRLF. Generujemy sumę kontrolną. Oba pliki przesy­ łamy (kopiujemy) do docelowej lokalizacji importu. Wykonujemy import poprzez uru­ chomienie drugiej aplikacji. Spotyka nas rozczarowanie, gdyż import się nie powiódł z powodu niezgodności wygenerowanej sumy z sumą przesłaną w załączonym pliku. Dlaczego? Jednym z powodów jest wystąpienie niejawnej konwersji znaku końca li­ nii w pliku wymiany danych w trakcie kopiowania. Kiedy istnieje takie zagrożenie? W momencie kopiowania pomiędzy systemami Windows i Linux. Jest to idealny

188

Testowanie oprogramowania. Podręcznik dla początkujących

przykład, a zarazem sposób na przetestowanie wymagania kontroli sumy kontrolnej podczas inicjacji importu. Konwersja znaku końca linii nastąpiła „w locie” i niejawnie. W wyniku tego zmieniła się zawartość pliku. Aplikacja docelowa wygenerowała su­ mę kontrolną, ale już na podstawie przekłamanych danych. To jest przyczyna tego, że porównanie obu sum może zakończyć się niepowodzeniem. Jedną z metod uniknięcia takiej przykrej niespodzianki jest wygenerowanie sumy kontrolnej już z miejsca docelowe­ go (po kopiowaniu) lub wygenerowanie pliku i sumy w miejscu źródłowym, a następ­ nie skopiowanie ich binarnie (nie powinno nastąpić przekłamanie). Wspomina sytuacja jest tak prosta i oczywista, że kuriozalnie może być powodem do frustracji w trakcie wykonywania testów. Internet oferuje wiele narzędzi do generowania i weryfikacji sumy kontrolnej wedle różnych algorytmów. Wspomniane narzędzia wydawane są zarówno na licencjach komercyjnych, jak i do darmowego używania. Każdorazowo jednak warto sprawdzić warunki licencji, gdyż często producenci zastrzegają darmowe użytkowanie w celach komercyjnych. Przykładowe narzędzia z interfejsem GUI: Advanced File Hash, Easy Hash. Z powodzeniem można wyszukać również generator online, np. http://www.

sha1-online.com/. Generowanie sumy kontrolnej z konsoli Linux: Algorytm SHA (ang. Secure Hash Algorithm: SHA-1, SHA-2) — przykład na listingu A.1.

Listing A.1. Generowanie sumy kontrolnej według algorytmu SHA1 [uzytkownik@KOMPUTER ~]$ c a t t e s t s u m y . t x t d ane, d ane, d ane, d ane, d ane, dane [uzytkownik@KOMPUTER ~]$ sha1sum t e s t s u m y . t x t > t e s t s u m y . s h a 1 [uzytkownik@KOMPUTER ~]$ c a t t e s t s u m y .s h a 1 93202a39a12 797be912fff4609bd7db65d225ed5 t e s t s u m y . t x t

Algorytm MD5 (ang. Message-Digest algorithm 5) — przykład na listingu A.2.

Listing A.2. Generowanie sumy kontrolnej według algorytmu MD5 [uzytkownik@KOMPUTER ~]$ md5sum t e s t s u m y . t x t > testsum y.m d5 [uzytkownik@KOMPUTER ~]$ c a t testsum y.m d5 14e19ce8e1699633d4a5f33db19b2f1d t e s t s u m y .t x t

Dodatek B

Membrane SOAP Monitor Membrane Monitor to narzędzie, które pozwala na przechwytywanie wiadomości HTTP oraz SOAP, a co najważniejsze — oferuje możliwość zatrzymania komunikatu np. w celu jego modyfikacji. Aplikację można pobrać ze strony domowej projektu: http:// www.membrane-soa.org/soap-monitor/. Wspomniane narzędzie wspiera obsługę SSL. Wspominałem wcześniej, że bywają sytuacje, kiedy testy wymagają wglądu w treść komunikatów wymienianych pomiędzy klientem a serwerem, np. w przypadku braku fizycznego dostępu do symulatora usługi sieciowej (logi, konfiguracja odpowiedzi itp.). W takiej sytuacji projektowane testy są istotnie zależne od możliwości zaślepki. Z zało­ żenia są one mocno ograniczone i nie zawsze zaspokoją nasze potrzeby. Narzędzie Membrane SOAP Monitor może poszerzyć możliwości wykonywania testów poprzez przechwycenie odpowiedzi serwera i manipulację treścią wiadomości, np. zmianę warto­ ści w tagach. Oczywiście możliwa jest również odwrotna sytuacja, tj. przechwycenie i zatrzymanie żądania do serwera. Po uruchomieniu aplikacji wybieramy opcję Add Proxy . Ukaże się kreator, który po­ prowadzi nas przez wstępną konfigurację (rysunek B.1). Po ustawieniu podstawowych parametrów powrócimy do głównego okna narzędzia (rysunek B.2). Za pomocą przycisku Edit wywołamy opcję dodatkowej konfiguracji nasłuchu (ry­ sunki B.3, B.4, B.5). Na zakładce Proxy Key definiujemy numer portu, na którym bę­ dzie nasłuchiwać monitor, oraz określamy hosty, dla których będzie przechwytywana komunikacja. Kolejna karta Target służy do zdefiniowania akcji, czyli tego, gdzie monitor ma przekierować ruch po przechwyceniu wiadomości (docelowy adres ser­ wera). Zakładka Actions umożliwia wybranie momentu blokady komunikacji (zapy­ tanie, odpowiedź).

190

Rysunek B.l. Membrane — kreator konfiguracji

Testowanie oprogramowania. Podręcznik dla początkujących

A d d a n e w Proxy

Add Q

© S im p le Service P roxy

C re ate s ervice p ro x y th a t fo rw a rd s H TTP a n d SOAP requests.

© A d v a n c e d Service P roxy

O ffers all a v a ila b le o p tio n s f o r service p ro xie s lik e v irtu a l ho st. H TTP m e th o d a n d re q u e s t U R L

© H T T P Proxy

W o rk s lik e a re g u la r H TTP Proxy, Can p ro x y SOAP an d H T T P requests.

N e x t>

Rysunek B.2. Membrane — główne okno programu

C ancel

Dodatek B ♦ Membrane SOAP Monitor

Rysunek B.3. Membrane — dodatkowa konfiguracja nasłuchu A

Rysunek B.4. Membrane — dodatkowa konfiguracja nasłuchu B

191

192

Testowanie oprogramowania. Podręcznik dla początkujących

Rysunek B.5. Membrane — dodatkowa konfiguracja nasłuchu C

Konfiguracja na powyższych ilustracjach realizować będzie założenie: przechwyty­ wanie ruchu dla wszystkich hostów (*) na porcie 3128. Po wychwyceniu wiadomości ma ona zostać skierowana na adres 127.0.0.1 i port 8088. Jednak zanim nastąpi zmiana trasy wiadomości, należy ją odblokować, gdyż włączona jest opcja Block Request. Odblokować (opcja Continue), tzn. dokonać ewentualnej edycji i „popchnąć” manualnie dalej (rysunek B.6). Z punktu widzenia testów klienta usług sieciowych bardziej interesującą opcją jest blokowanie odpowiedzi nadchodzącej z serwera w celu ewentualnej modyfikacji treści. Niejednokrotnie wspominałem, że symulatory z reguły mają ograniczoną logikę bizne­ sową. Membrane Monitor umożliwia ingerencję w treść komunikatu (rysunki B.7 i B.8). Rysunek B.9 prezentuje podgląd treści zmodyfikowanej odpowiedzi (tag ). Należy zwrócić uwagę na adres endpoint, na który było wysłane żądanie ( 127.0.0.1:3128). Jest to adres monitora, który przechwycił wiadomość i przesłał ją do serwera usługi sieciowej pod adresem 127.0.0.1:8088 .

Dodatek B ♦ Membrane SOAP Monitor

Rysunek B.6. Membrane — blokowanie przechwyconej wiadomości (Request) Rysunek B.7. Membrane — blokowanie odpowiedzi z serwera (response)

193

19 4

Testowanie oprogramowania. Podręcznik dla początkujących

Rysunek B.8. Membrane — edycja przechwyconej wiadomości (response)

Rysunek B.9. SoapUI — podgląd zmodyfikowanej odpowiedzi

Dodatek C

Wireshark — analizator ruchu sieciowego Wireshark to potężne i wysoko specjalistyczne narzędzie służące do analizowania ruchu sieciowego. Przystosowanie tego programu do własnych potrzeb może okazać się kłopotliwe, o ile ktoś pierwszy raz ma styczność z tą aplikacją. Stwarza ona wrażenie bardzo skomplikowanej, co nie jest bezpodstawne, biorąc pod uwagę większość moż­ liwości drzemiących w tym narzędziu. Program można pobrać ze strony domowej projektu: http://www.wireshark.org/. Pozwolę sobie ograniczyć się w tej książce jedynie do przedstawienia tego narzędzia. Rysunek C.1 prezentuje główne okno programu. Podstawowe czynności to skonfigu­ rowanie nasłuchu, np. TCP or UDPport 80 (rysunek C.2), oraz wybranie protokołów, które mają być analizowane (rysunek C.3).

Rysunek C.1. Wireshark—

Capturing from Poi^czenie lokalne (port 8080) File

Edit

View

Go

Capture

Analyze

[W ireshark 1,10,3 (SVN Rev 53022 from /trunk-1.10)]

Statistics

Telephony

Tools

Internals

główne okno programu

Help

Expres sic Time 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

S S EE EE

O

Destination

Protocol

: 6 0 b y t e s o n w i r e ( 4 8 0 bits), n , src: ibm_ Pro t o c o l V e r s i o n 4 , Src: b ytes)

00000000 00100101 0 0 1 0 0 1 0 1 10 1 0 1 0 1 1 00000000 00101000 00011101 01000010 0 0 0 1 0 0 0 1 10 0 1 1 1 0 1 1 0 0 0 0 0 1 1 11 1 0 0 0 0 1 00100000 00010100 I Ready to load or captur

Length

IP v 4 IP v 4 IP v 4 IP v 4 IP v 4 IP v 4 IP v 4 IP v 4 IP v 4 IP v 4 IP v 4 IP v 4 IP v 4 IP v 4 IP v 4

0 .9 6 6 3 9 5 0 0 0 3 .4 9 1 7 5 8 0 0 0 3 .692067000 1 8 .756830000 1 8 .757193000 1 8 .757197000 1 8 .757307000 1 9 .7 5 7 8 1 1 0 0 0 1 9 .758310000 1 9 .758315000 1 9 .758439000 3 5 .001887000 3 5 .002211000 3 5 .0 0 2 2 1 5 0 0 0 3 5 .002331000

Frame 2 2 Ethernet Internet Data ( 2 0

0000 0008 0010 0018 0020 0028 0030

Source

01100100 00001011 10101111 10101100 00011111 01111001 00010110

60

01110100 11011110 10111001 00011011 10010000 01110001 11011110

by t e s c a p t u r e d ( 4 8 0 , Dst: Dell

11110010 01100100 00001000 00000000 01000000 00000000 00000100 00000001 11110111 10010010 11000010 10001000 00000000 00000000

Packets: 23 ■Displayed: 23 (100,0%)

60 14 50 54 54 60 60 54 54 60 60 54 54 60 60 54

Info TCP ( 6 ) TCP ( 6 ) TCP ( 6 ) TCP ( 6 ) TCP ( 6 ) TCP ( 6 ) TCP ( 6 ) TCP ( 6 ) TCP ( 6 ) TCP ( 6 ) TCP ( 6 ) TCP ( 6 ) TCP ( 6 ) TCP ( 6 ) TCP ( 6 )

bits) on i n t e r f a c e 0

00000000 01000101 01000000 10101100 00110100 01010000 00000000

00010001 00000000 00000110 00011011 00001110 00010001 00000000 Profile: Default

. % d t. d . % E

.(. [email protected]



196

Testowanie oprogramowania. Podręcznik dla początkujących

Rysunek C.2. Wireshark— konfiguracja nasłuchu A

Rysunek C.3. Wireshark — konfiguracja nasłuchu B Bogactwo możliwości może okazać się przeszkodą w dostosowaniu narzędzia do po­ trzeb testów. Niemniej jednak dobrze mieć w zanadrzu oprogramowanie wspomagające testy o różnym poziomie zaawansowania. Wireshark wspiera SSL.

Dodatek D

Generowanie danych testowych Nieuchronnie każdy tester stanie przed koniecznością posłużenia się dużą ilością da­ nych o jakości (wartości) zbliżonej do rzeczywistych danych, jakie będą przepływać przez system. Przy profesjonalnym podejściu do procesu weryfikacji oprogramowania należy sprzeciwiać się pracy wyłącznie na danych o „śmieciowej” wartości, tj. takich danych, które nie niosą wymiernej informacji, a jedynie stanowią wypełniacz bazy danych. Bardzo szczegółowe i specyficzne testy znacznie łatwiej jest prowadzić przy użyciu poważnie zawężonego zakresu danych. Nie ma nic złego w takim podejściu, gdyż wspomniany stan rzeczy ułatwia weryfikacj ę wyniku oraz ewentualną analizę problemu. Niemniej jednak kiedy już nabierzemy wystarczającego zaufania do logiki (biznesu) testowanej funkcjonalności, warto pokusić się o poszerzenie testów w uję­ ciu masowego przetwarzania danych. Zapewne nie wszystkie obszary systemu będą wymagały takiej weryfikacji. Niemniej jednak funkcjonalności związane z importem i eksportem danych, generowaniem i prezentacją raportów, stronicowaniem danych, przetwarzaniem masowym w systemach korowych etc. powinny podlegać testom uwzględniającym hurtową ilość danych. Testy ilościowe powinny dać odpowiedź, jak system radzi sobie z dużą ilością danych. Do podstawowych punktów pomiaru należy zaliczyć: ♦ sukces: zasileń, generowania raportów, przetwarzań; ♦ sukces + użycie wszystkich przewidzianych danych (system nie powinien gubić/pomijać bezzasadnie danych); ♦ logikę biznesową zachowującą się analogicznie przy dużej i małej ilości danych (chyba że zapisy wymagań określają sytuacj ę inaczej). Testy ilościowe dobrze jest prowadzić w oparciu o dane bardzo zbliżone do rzeczywi­ stych. W miarę możliwości istotne jest wprowadzanie relatywnie dużej różnorodności informacji, jakie niosą dane. Należy również pamiętać o preparowaniu danych, któ­ rych import z założenia powinien zakończyć się niepowodzeniem. Oprzyjmy dalsze rozważanie na hipotetycznej sytuacji importu pliku płaskiego, który służy do wymiany

198

Testowanie oprogramowania. Podręcznik dla początkujących

danych pomiędzy dwoma różnymi systemami. Rzeczą oczywistą jest, że znamy spe­ cyfikację pliku, tj. liczbę pól, typy danych, separatory pól itp. Przyjmijmy, że kolumn (pól) będzie 20. Weryfikując logikę, dotychczas posługiwaliśmy się co najwyżej kilku­ nastoma wierszami. Nadszedł czas, aby poddać system właściwej próbie ognia i tym samym zwiększyć zakres danych do 30 000 wierszy. Trudno sobie wyobrazić, aby te­ ster preparował taki plik „ręcznie”. Byłoby to nieefektywne i żmudne, a efekt końcowy mógłby być niezadowalający. W takich sytuacjach z powodzeniem można się posił­ kować gotowymi narzędziami, tzn. generatorami danych testowych, o których będzie mowa na poniższych kartach tego rozdziału. Wróćmy do naszego pliku. Idealną sy­ tuacją jest wykonanie importu hurtowej ilości danych, których kombinacja (wartości i struktura) zmuszą system do maksymalnie wytężonego wysiłku. Poprzez wspomnianą ekspresję mam na myśli dotknięcie jak największej liczby linii kodu w trakcie prze­ twarzania pliku. Zatem należy zadbać, aby pewien procent wierszy oprogramowanie uznało za błędne (dane, strukturę linii). Błędne wiersze dobrze jest rozmieścić asyn­ chronicznie w całym obszarze pliku. Trudność w spreparowaniu linii poprawnych jest mocno zależna od poziomu powiązania (walidacji) danych importowanych z danymi faktycznie istniejącymi w systemie docelowym. Załóżmy, że importujemy kampanię promocyjną realizowaną poprzez wiadomość SMS. Jeżeli system odrzuca wiersze, dla których nie znalazł w bazie faktycznie istniejącego abonenta, pomimo iż wszelkie po­ zostałe reguły zostały spełnione, to sytuacja robi się nieco skomplikowana. Nadmie­ niona komplikacja dotyczy trudności w „wyprodukowaniu” hurtowej ilości poprawnych danych z uwagi na silne algorytmy walidacyjne, które bazują na już istniejących danych w bazie. Upraszczając: możemy mieć pewien kłopot z wygenerowaniem danych, które łatwo uda się dopasować do aktualnego stanu bazy danych tak, aby wiersze zostały uznane za poprawne (najczęściej w aspekcie biznesowym). Preparując plik w gene­ ratorze danych, z reguły otrzymamy losowy identyfikator klienta, który niekoniecznie znajdzie odwzorowanie w bazie docelowej. Co możemy uczynić, aby zrealizować im­ port? Jeżeli jest to nasz jedyny problem, możemy spróbować podmienić wartości w kło­ potliwej kolumnie, posługując się półśrodkami, np. arkuszem kalkulacyjnym. Reko­ menduję tę praktykę, jeśli chce się uzyskać maksymalną różnorodność danych. W sytuacji kiedy system pozwala na import 30 000 identycznych wierszy (dla tego samego iden­ tyfikatora klienta), można najzwyczajniej powielić interesującą nas liczbę wierszy, choć traktowałbym ten zabieg jako rozwiązanie ostateczne czy wręcz awaryjne. Reasumując: importowany plik powinien zawierać pewien odsetek wierszy błędnych (o różnej przyczynie), dużą liczbę różnorodnych danych (dla wielu klientów) oraz nieść infor­ mację o rzeczywistym znaczeniu (nie zaśmiecać bazy). Warto nadmienić, że istotnym parametrem determinującym podejście do produkcji pliku importu jest zachowanie systemu w razie wykrycia błędu w trakcie importu. Jeżeli oprogramowanie realizuje funkcjonalność masowego zasilania jako operację atomową, tj. taką, która musi po­ wieść się w całości lub zostanie wycofana, to nieco inaczej przygotujemy wiersze błędne (w tym przypadku będzie to pułapka w pliku). Wspomnianą pułapkę należy zastawić raz na końcu pliku w celu zweryfikowania, czy np. po przetworzeniu 25 000 wierszy system je wycofa. Drugi raz trzeba wprowadzić błędny wiersz na początku w celu oceny, czy system przerwie i wycofa proces. Jeżeli import nie ma znamion opera­ cji atomowej, to błędne dane zwykle zostają porzucone (oznaczone jako błędne), a po­ prawne „trafią” tam, gdzie przewiduje projekt.

Dodatek D ♦ Generowanie danych testowych

199

Z jednego z powyższych akapitów wynika, że generatory danych nie stanowią pana­ ceum na wszelkie problemy związane z testami ilościowymi. Bywa, że uda się przy­ gotować dane idealnie pasujące do potrzeb, np. plik SQL, który wstawi dane do bazy. Bywa również, że wygenerowany zestaw danych stanowi półprodukt, który trzeba do­ stosować do indywidualnych potrzeb — konieczna jest np. konwersja znaku końca linii, zmiana separatora pól, dostosowanie XML do komunikatu SOAP jako żądania web service itp. Oprócz problemów czysto technicznych możemy mieć również kłopot z dopasowaniem pozyskanych danych do rzeczywistych potrzeb, np. w polach typu „nazwa miasta” generator „wstawi” nazwy miejscowości rodem z Wielkiej Brytanii, gdy system będzie pracował z „polskimi danymi”. Stwarza to pewien problem, gdyż dla systemu „podstawione” dane będą zgodne z regułami walidacyjnymi, ale dla użytkownika mogą wydawać się nieprzyjemne w użyciu. Niemniej jednak doświad­ czony tester poradzi sobie również w takiej sytuacji. Generatory danych testowych są bardzo pomocne w sytuacjach, kiedy ewentualna logika w trakcie przetwarzania re­ alizowana jest w tle przez system i tester nie musi się interesować, co dzieje się „pod spodem”. Równie przydatne mogą okazać się w trakcie przygotowania wsadu (da­ nych) do testów niefunkcjonalnych (wydajnościowych), np. do wygenerowania 100 komunikatów XML. Generator danych testowych może również posłużyć do sprepa­ rowania pliku, którym tylko zasilimy odpowiednio bazę danych, a uzyskane w ten spo­ sób źródło będzie wykorzystane przez zupełnie inny proces. Sytuacja znacznie bardziej komplikuje się, kiedy potrzebujemy dużej ilości danych, ale nie możemy ich w prosty sposób „wstawić” do bazy. Załóżmy, że chcemy spraw­ dzić generowanie raportu dla 50 000 klientów (w naszych rozważaniach kontekst in­ formacji nie jest potrzebny). Raport wykorzystuje dane z wielu różnych tabel, których część jest zasilana poprzez procesy, które są bardzo trudne do „podrobienia”. Oczywi­ ście korelacja pomiędzy tabelami jest wysoce silna. Wprowadzenie spójnych danych do kilku tabel będzie zabiegiem karkołomnym. Jedyną rozsądną drogą jest przygotowa­ nie danych „po bożemu” poprzez „wyklikanie” danych w systemie. W takich sytuacjach niezmiernie użyteczne okazują się skrypty z automatyzacji testów, np. dla testów regresywnych. Automatyzacja testów również może być wykorzystana do generowania uczciwych danych testowych w sposób szybki i nienużący testera. Warto zapamiętać, że automaty testowe można zaangażować również do preparowania danych testowych, np. skryptu zakładającego użytkownika, który po 100-krotnym przetworzeniu stworzy całkiem pokaźną grupę reprezentantów np. do raportu. Więcej informacji o automaty­ zacji testów znajduje się w rozdziale 8. niniejszej publikacji. W analogiczny sposób można potraktować narzędzia do automatycznych testów wydaj­ nościowych, np. Apache JM eter . Tester może zaprojektować przypadek, który w pętli będzie powtarzał określoną czynność (np. insert lub wywołanie funkcji WS) i syste­ matycznie będzie inicjował generowanie danych. Jest to rozwiązanie niezmiernie ela­ styczne, gdyż w czasie rzeczywistym można monitorować ilość pozyskiwanych danych i nią sterować. Nie wymaga ono również uporczywej pracy przy powielaniu liczby wierszy w pliku. Wystarczy przygotować jedno uniwersalne zdarzenie, które będzie uwzględniało potrzebę generowania różnorodnych danych, a następnie je wielokrotnie wykonywać. Zwykle zasilenia z plików są jednokrotnego użytku, a dobrze przygoto­ wany test w JMeter można realizować wielokrotnie bez konieczności modyfikacji. Narzędzie Apache JMeter zostało opisane w rozdziale poświęconym testom wydajno­ ściowym.

200

Testowanie oprogramowania. Podręcznik dla początkujących

Internet oferuje szereg narzędzi umożliwiających generowanie danych w trybie online. Jedno z nich zamieszczone jest na stronie http://www.generatedata.com/ . Wniesienie relatywnie niewielkiej opłaty poszerza zakres możliwości wspomnianego narzędzia, tj. umożliwia wygenerowanie większej liczby wierszy niż 100. Rysunek D.1 prezen­ tuje interfejs wspomnianego narzędzia.

Rysunek D.1. Generator danych testowych Generatedata.com oferuje eksport danych w wielu różnych formatach (sekcja EXPORT TYPES ), w tym SQL, XML, CSV. Format eksportu może być dodatkowo spersonali­ zowany według naszych potrzeb. Przykładowo dla CSV można ustawić separator pól oraz znak końca linii (rysunek D.2). Dla opcji SQL można wybrać między innymi typ bazy danych oraz akcję, jaka ma zostać wykonana (rysunek D.3). Opcja XM L umoż­ liwia zdefiniowanie własnego formatu pliku (opcja Use custom XM L fo rm a t ) — ry­ sunek D.4. Sekcja DATA SE T służy do definiowania nazw pól oraz typu danych, które mają zostać wygenerowane (rysunek D.5). W górnej części interfejsu znajduje się opcja COUNTRY-SPECIFIC D ATA , która służy do zdefiniowania formatu generowa­ nych danych w kontekście wybranego kraju, np. jeśli zdecydowaliśmy się zastosować wzorzec z danymi „niemieckimi”, to algorytm narzędzia będzie się starał wygenero­ wać dane zbliżone do rzeczywistych, np. dopasuje format kodu pocztowego lub numer telefonu specyficzne dla Niemiec.

Dodatek D ♦ Generowanie danych testowych

201

Rysunek D.2. Generator danych testowych CSV E X P O R T TYPES ® CSV

Excel

HTML

JSON

P ro g ra m m in g L a n g ua ge

D a ta b a s e ta b le n a m e

|ta b e la T e s to w a

D a ta b a s e T y p e

| O ra c le 1

Mise O p tio n s

SQL |

0

H l In c lu d e CREATE T ABLE q u e r y IH In c lu d e DROP TABLE q u e ry

m

XM L

LD IF

S ta te m e n t T y p e

P rim a ry K e y

- hide data Format optior

'9

IN SERT

©

UPDATE

©

None

W Add

d e fa u lt a u to -in c re m e n t colu m n

E nclose t a b le and fie ld n a m e s w ith b a c k q u o te s

Rysunek D.3. Generator danych testowych SQL

Rysunek D.4. Generator danych testowych XML

Rysunek D.5. Generator danych testowych SQL — specyfikacja kraju Rysunek D.6 przedstawia kod wygenerowany w oparciu o omawiane narzędzie zgodnie z konfiguracją z rysunku D.5. Rysunek D.7 pokazuje skutek wykonania tak spreparo­ wanego skryptu na bazie MySQL. Przytoczony przykład jest bardzo prosty i ma wartość w zasadzie akademicką. Jednak w wystarczający sposób obrazuje możliwości gene­ ratorów danych i sposób użycia pozyskanych plików źródłowych.

202

-

Testowanie oprogramowania. Podręcznik dla początkujących

UMUF TADLE

.d Ł ild .e s L u » « ' :

CREATE TADLE ' L a b e la T v s lO w « ' (

3

4 5 C

'Td‘ mr

Nr telefonu: c4d>

4 d > 1 00-200-300 O td>