Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
01278 012657 11048702 na godz. na dobę w sumie
Sztuka testowania oprogramowania - książka
Sztuka testowania oprogramowania - książka
Autor: , , , Liczba stron: 272
Wydawca: Helion Język publikacji: polski
ISBN: 83-7361-894-5 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> inne - programowanie
Porównaj ceny (książka, ebook, audiobook).

Testowanie to ostatni i niestety czasem pomijany element procesu tworzenia oprogramowania. Tymczasem ten właśnie etap powinien być niezwykle znaczącą częścią projektu. Znaczenie testowania dostrzegano już w początkowym okresie dynamicznego rozwoju technologii tworzenia oprogramowania, jednak nadal trudno jest znaleźć jasny i czytelny zbiór reguł testowania i metodyki, w oparciu o które proces ten należy przeprowadzać. Testy oprogramowania często przeprowadzane są przez jego twórców lub osoby przypadkowe, co zdecydowanie nie zdaje egzaminu.

'Sztuka testowania oprogramowania' to książka traktująca wyłącznie o testowaniu oprogramowania. Przedstawia zasady testowania kodu źródłowego, pojedynczych modułów programu oraz całej aplikacji. Zawiera cenne wskazówki dla testerów dotyczące przygotowywania przypadków testowych i metodologii testowania. Autorzy opisali w niej również metodykę testowania ekstremalnego i sposoby testowania aplikacji internetowych.

Zadbaj o to, aby tworzone przez Ciebie programy były pozbawione błędów.

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

IDZ DO IDZ DO PRZYK£ADOWY ROZDZIA£ PRZYK£ADOWY ROZDZIA£ SPIS TREĎCI SPIS TREĎCI KATALOG KSI¥¯EK KATALOG KSI¥¯EK KATALOG ONLINE KATALOG ONLINE ZAMÓW DRUKOWANY KATALOG ZAMÓW DRUKOWANY KATALOG TWÓJ KOSZYK TWÓJ KOSZYK DODAJ DO KOSZYKA DODAJ DO KOSZYKA CENNIK I INFORMACJE CENNIK I INFORMACJE ZAMÓW INFORMACJE ZAMÓW INFORMACJE O NOWOĎCIACH O NOWOĎCIACH ZAMÓW CENNIK ZAMÓW CENNIK CZYTELNIA CZYTELNIA FRAGMENTY KSI¥¯EK ONLINE FRAGMENTY KSI¥¯EK ONLINE Wydawnictwo Helion ul. Chopina 6 44-100 Gliwice tel. (32)230-98-63 e-mail: helion@helion.pl Sztuka testowania oprogramowania Autor: Glenford J. Myers, Corey Sandler, Tom Badgett, Todd M. Thomas T³umaczenie: Andrzej Gra¿yñski ISBN: 83-7361-894-5 Tytu³ orygina³u: The Art of Software Testing, Second Edition Format: B5, stron: 272 Testowanie to ostatni i niestety czasem pomijany element procesu tworzenia oprogramowania. Tymczasem ten w³aġnie etap powinien byæ niezwykle znacz¹c¹ czêġci¹ projektu. Znaczenie testowania dostrzegano ju¿ w pocz¹tkowym okresie dynamicznego rozwoju technologii tworzenia oprogramowania, jednak nadal trudno jest znaleĥæ jasny i czytelny zbiór regu³ testowania i metodyki, w oparciu o które proces ten nale¿y przeprowadzaæ. Testy oprogramowania czêsto przeprowadzane s¹ przez jego twórców lub osoby przypadkowe, co zdecydowanie nie zdaje egzaminu. „Sztuka testowania oprogramowania” to ksi¹¿ka traktuj¹ca wy³¹cznie o testowaniu oprogramowania. Przedstawia zasady testowania kodu ĥród³owego, pojedynczych modu³ów programu oraz ca³ej aplikacji. Zawiera cenne wskazówki dla testerów dotycz¹ce przygotowywania przypadków testowych i metodologii testowania. Autorzy opisali w niej równie¿ metodykê testowania ekstremalnego i sposoby testowania aplikacji internetowych. • Podstawowe zasady testowania programów • Inspekcja kodu ĥród³owego • Przypadki testowe • Testowanie pojedynczych modu³ów aplikacji • Testowanie funkcjonalne, systemowe, akceptacyjne i instalacyjne • Usuwanie b³êdów • Regu³y testowania ekstremalnego • Testowanie aplikacji internetowych Zadbaj o to, aby tworzone przez Ciebie programy by³y pozbawione b³êdów. Spis treści Przedmowa Wprowadzenie 1. Samoocena zdolności testera 7 9 13 2. Psychologiczne i ekonomiczne aspekty testowania programów 19 Psychologia testowania ...................................................a............................20 Ekonomika testowania ...................................................a...........................23 Test „czarnej skrzynki” ...................................................a......................24 Test „białej skrzynki” ...................................................a.........................26 Zasady testowania programów ...................................................a..............29 Podsumowanie ...................................................a.........................................36 3. Inspekcja programów, wędrówka po kodzie źródłowym i przegląd kodu 39 Inspekcje i wędrówki po kodzie ...................................................a.............40 Inspekcja kodu ...................................................a.........................................42 Lista kontrolna błędów programistycznych na użytek inspekcji kodu .....45 Błędy w odwołaniach do danych ...................................................a......45 Błędy w deklaracjach danych ...................................................a............48 Błędy obliczeniowe ...................................................a.............................50 Błędy porównywania ...................................................a.......................... 51 Błędy przepływu sterowania ...................................................a..............53 Błędy interfejsu ...................................................a....................................55 Błędy wejścia-wyjścia ...................................................a...........................56 Inne błędy ...................................................a............................................57 Wędrówki po kodzie ...................................................a...............................60 Kontrola przy biurku ...................................................a.............................. 61 4 S Z T U K A T E S T O W A N I A O P R O G R A M O W A N I A Wzajemna ocena ...................................................a......................................62 Podsumowanie ...................................................a.........................................63 4. Projektowanie przypadków testowych 65 Przypadki testowe dla testów „białej skrzynki” ......................................67 Testowanie pokrycia kodu ...................................................a.................67 Podział na klasy równoważności ...................................................a......75 Przykład ...................................................a................................................79 Analiza wartości granicznych ...................................................a...........83 Grafy przyczynowo-skutkowe ...................................................a........... 91 Zgadywanie błędów ...................................................a................................113 Strategia ...................................................a...................................................a 115 5. Testowanie modułów (jednostek) 117 Projektowanie przypadków testowych ...................................................a 118 Testowanie przyrostowe ...................................................a........................ 132 Testowanie zstępujące a testowanie wstępujące .................................... 138 Testowanie zstępujące ...................................................a...................... 138 Testowanie wstępujące ...................................................a..................... 145 Porównanie ...................................................a........................................147 Przeprowadzanie testów ...................................................a........................149 6. Testowanie wysokopoziomowe 151 Testowanie funkcjonalne ...................................................a...................... 157 Testowanie systemowe ...................................................a........................... 158 Testowanie możliwości ...................................................a.................... 161 Testowanie objętościowe ...................................................a.................. 161 Testowanie przeciążeń ...................................................a...................... 162 Testowanie użyteczności ...................................................a.................. 164 Testowanie ochrony danych ...................................................a........... 166 Testowanie efektywności ...................................................a.................. 166 Testowanie pamięci ...................................................a.......................... 167 Testowanie konfiguracji ...................................................a................... 167 Testowanie zgodności i konwersji ...................................................a.. 168 Testowanie procedury instalacyjnej .................................................. 168 Testowanie niezawodności ...................................................a.............. 168 Testowanie funkcji ratunkowych ...................................................a...170 Testowanie możliwości obsługi ...................................................a...... 171 Testowanie dokumentacji ...................................................a................ 171 Testowanie procedur ...................................................a........................172 Przeprowadzanie testów ...................................................a...................172 S P I S T R E Ś C I 5 Testowanie akceptacyjne ...................................................a....................... 173 Testowanie instalacyjne ...................................................a........................174 Planowanie i kontrolowanie testów ...................................................a.... 175 Kryteria zakończenia testu ...................................................a...................178 Niezależne agencje testujące ...................................................a................. 185 7. Debugowanie 187 Debugowanie „na siłę” ...................................................a.........................189 Debugowanie przez indukcję ...................................................a............... 191 Debugowanie przez dedukcję ...................................................a.............. 195 Debugowanie przez nawracanie ...................................................a......... 200 Debugowanie przez testowanie ...................................................a............201 Reguły debugowania ...................................................a.............................201 Reguły lokalizowania błędów ...................................................a........ 202 Techniki poprawiania błędów ...................................................a........203 Analiza błędów ...................................................a.......................................205 8. Testowanie ekstremalne 209 Podstawy programowania ekstremalnego .............................................210 Testowanie ekstremalne — koncepcja ...................................................a 216 Ekstremalne testowanie jednostek ...................................................a. 216 Testowanie akceptacyjne ...................................................a.................218 Testowanie ekstremalne — praktyka ...................................................a. 220 Projektowanie przypadków testowych ..............................................221 Aplikacja i jej sterownik testowy ...................................................a.... 224 Podsumowanie ...................................................a.......................................225 9. Testowanie aplikacji internetowych 227 Podstawowa architektura aplikacji e-commerce .................................. 229 Wyzwania związane z testowaniem ...................................................a..... 231 Strategie testowania ...................................................a...............................235 Testowanie warstwy prezentacji ...................................................a......237 Testowanie warstwy biznesowej ...................................................a......241 Testowanie warstwy danych ...................................................a........... 244 A Przykładowa aplikacja do testowania ekstremalnego B Liczby pierwsze mniejsze niż 1000 Słownik Skorowidz 249 255 257 263 3 Inspekcja programów, wędrówka po kodzie źródłowym i przegląd kodu Przez wiele lat powszechne było wśród programistów przekonanie, że program przeznaczony jest wyłącznie do wykonywania przez kom- puter, nie do czytania przez człowieka, a więc testowanie programu nie może odbywać się inaczej, jak tylko przez uruchamianie go na komputerze. Mniej więcej we wczesnych latach 70. ubiegłego wieku programiści zaczęli jednak stopniowo doceniać także znaczenie „bezkomputerowego” czytania kodu jako integralnej części wszech- stronnego procesu testowania. Co prawda nie wszyscy programiści zwykli studiować kody źró- dłowe w poszukiwaniu błędów, sama jednak koncepcja takiego czy- tania zyskała sobie ogólnie przychylne przyjęcie. Jej praktyczna re- alizacja uwarunkowana jest kilkoma czynnikami, między innymi rozmiarem i złożonością programu, rygoryzmem harmonogramów, liczebnością zespołu testującego, kwalifikacjami jego członków itp. Przed przystąpieniem do omawiania tradycyjnych, „maszyno- wych” technik testowania poświęcimy nieco uwagi testowaniu bez- komputerowemu. Okazuje się ono zadziwiająco efektywne pod wzglę- dem wykrywania błędów — efektywne tak dalece, że przy realizacji 4 0 S Z T U K A T E S T O W A N I A O P R O G R A M O W A N I A dowolnego projektu informatycznego należy jego zastosowanie przy- najmniej rozważyć; szczególnie polecane jest ono bezpośrednio po zakończeniu tworzenia kodu programu, jeszcze przed przystąpieniem do jego komputerowego testowania, choć może okazać się użyteczne także we wcześniejszych stadiach (etapach) kodowania (rozwinięcie tej kwestii wykraczałoby jednak poza ramy niniejszej książki). Na początek jednak istotne spostrzeżenie. Jako że testowanie programu przez człowieka odbywa się zwykle za pomocą metod mniej formalnych niż matematyczna weryfikacja kodu (przez komputer), naturalne stają się obawy, czy rezultaty tak prostego i mało rygory- stycznego postępowania mogą mieć jakąkolwiek wartość praktycz- ną. Otóż mogą, i choć takie nieformalne postępowanie nie może stanowić głównej metody testowania, to jednak może testowanie to uczynić bardziej produktywnym i wiarygodnym — z dwóch powodów. Po pierwsze, im wcześniej wykryte zostaną błędy, tym mniejszy będzie koszt ich naprawienia i mniejsze prawdopodobieństwo po- myłki przy naprawianiu. Po drugie, z chwilą rozpoczęcia testowania maszynowego programiści ulegają swoistej presji mentalnej, ukie- runkowanej na szybkie osiągnięcie sukcesu („jak najszybciej uporać się z tym nieznośnym błędem!”), co zwykle zwiększa zagrożenie wpro- wadzania nowych błędów przy usuwaniu istniejących. Mniej for- malne postępowanie „bezkomputerowe” jest od tego typu presji za- zwyczaj wolne. Inspekcje i wędrówki po kodzie Wędrówki po kodzie (walkthrougs) oraz jego inspekcje (inspections) to dwie główne metody bezkomputerowego testowania. Ponieważ są one pod wieloma względami podobne do siebie, zajmiemy się najpierw tymi podobieństwami, odkładając na nieco później omówienie róż- nic między nimi. Zarówno wędrówki po kodzie, jak i inspekcja kodu polegają na wizualnym studiowaniu kodu przez zespół testowy. Celem tego jest jedynie wykrywanie błędów, nie ich poprawianie — wszak mamy do czynienia z testowaniem, nie z debugowaniem. Zespół powinien pracować w klimacie porozumienia, w dążeniu do wspólnego celu, powinien też być odpowiednio przygotowany do działania. Powodze- nie (albo niepowodzenie) wspólnego wysiłku uwarunkowane jest wie- loma czynnikami, których większość omówiliśmy w rozdziale 2. I N S P E K C J A P R O G R A M Ó W , W Ę D R Ó W K A P O K O D Z I E . . . 4 1 Wędrówka po kodzie sprowadza się do jego uważnego przeglądu, dokonywanego przez zespół (optymalnie) trzech lub czterech teste- rów. Tylko jeden z nich jest autorem (lub współautorem) programu, pozostali nie są związani z jego tworzeniem — zgodnie z regułą nr 2 z poprzedniego rozdziału. Jest to sytuacja znacznie korzystniejsza (z perspektywy powodzenia testów) w porównaniu z samodzielnym studiowaniem kodu przez jego autora (tzw. „kontrola na biurku” — desk-checking). Inną zaletą wędrówek po kodzie, przekładającą się bezpośrednio na niższe koszty poprawiania błędów, jest możliwość precyzyjnego umiejscawiania wykrywanych błędów w kodzie źródłowym. Zazwy- czaj wykrywa się wówczas całe grupy powiązanych ze sobą błędów, które później mogą być w sposób grupowy eliminowane. Nie ma tej zalety testowanie maszynowe, pozwalające jedynie na obserwację symp- tomów błędów (program „zawiesza się” bądź na wydruku pojawiają się bezsensowne wartości) i umożliwiające wykrywanie tylko jednego błędu na raz. Inspekcja i wędrówki kodu umożliwiają wykrycie średnio 30 – 70 procent błędów związanych z logiką programu i kodowaniem, są jednak zwykle nieefektywne w odniesieniu do poważniejszych błędów projektowych, jak błędy w procesie analizy wymagań (requirement analy- sis). Nie oznacza to oczywiście, że można w ten sposób wykryć do 70 wszystkich błędów, bo — jak wyjaśnialiśmy w rozdziale 2. — liczba wszystkich błędów tkwiących w programie zawsze pozostaje niewia- doma; owe 70 odnosi się raczej do wszystkich błędów wykrytych w całym procesie testowania. Swoją drogą warto zachować pewien krytycyzm (sceptycyzm?) co do przedstawionej statystyki, bezkomputerowe testowanie umożliwia bowiem wykrywanie raczej „prostych” błędów — te bardziej subtel- ne, zakamuflowane ujawniają się przeważnie tylko w testowaniu ma- szynowym. To poniekąd prawda, jak jednak wskazuje doświadczenie wielu testerów, testowanie bezkomputerowe okazuje się skuteczniejsze od maszynowego w stosunku do pewnych szczególnych rodzajów błędów, powinno więc być traktowane jako jego wartościowe uzupełnienie. Chociaż testowanie bezkomputerowe okazuje się użyteczne w od- niesieniu do nowo tworzonych programów, może być równie (jeśli nie bardziej) praktyczne w stosunku do modyfikacji programów ist- niejących. Dokonywanie zmian w istniejących (i przetestowanych) 4 2 S Z T U K A T E S T O W A N I A O P R O G R A M O W A N I A programach jest czynnością znacznie bardziej podatną na błędy (w sensie średniej ilości błędów przypadających na jedną dodawaną lub zmienianą instrukcję) niż tworzenie nowych programów. Testo- wanie bezkomputerowe okazuje się w tym kontekście wartościowym uzupełnieniem (maszynowego) testowania regresywnego. Inspekcja kodu Inspekcja kodu to zestaw procedur i technik wykrywania błędów w ramach czytania kodu przez grupę ludzi. Większość dyskusji zwią- zanych z inspekcją kodu koncentruje się wokół procedur, formula- rzy do wypełnienia itp.; po krótkim wprowadzeniu w ogólne za- gadnienia inspekcji zajmiemy się więc szczegółowo poszczególnymi technikami wykrywania błędów. Zespół dokonujący inspekcji składa się zazwyczaj z czterech osób. Jedną z nich jest moderator, z założenia doświadczony programista, niezwiązany jednak z analizowanym (testowanym) programem i nie- wtajemniczony w jego szczegóły. Do podstawowych obowiązków moderatora należą między innymi: organizacja sesji inspekcyjnych i dystrybucja niezbędnych ♦ materiałów, kierowanie sesjami inspekcyjnymi, rejestrowanie wszystkich stwierdzonych błędów, zapewnienie, że wykrywane błędy są konsekwentnie ♦ ♦ ♦ poprawiane. Moderator jest więc kimś w rodzaju inżyniera kontroli jakości. Pozostali członkowie zespołu to (zwykle) programista (autor progra- mu), projektant programu (nie mylić z programistą) oraz specjalista od testów. Listing programu i jego specyfikacja projektowa dostarczane są przez moderatora pozostałym członkom zespołu na kilka dni przed rozpoczęciem sesji. Członkowie zespołu powinni zapoznać się do- kładnie ze wspomnianymi materiałami, zaś sam przebieg sesji spro- wadza się głównie do dwojakiego rodzaju czynności: 1. Programista — jako narrator — odczytuje kolejne instrukcje programu, zaznajamiając z jego logiką pozostałych członków zespołu. Ci ostatni mogą w tym czasie zadawać pytania, I N S P E K C J A P R O G R A M Ó W , W Ę D R Ó W K A P O K O D Z I E . . . 4 3 powinni też na bieżąco śledzić tok narracji w celu zauważenia ewentualnych niejasności w logice programu (i wykrycia w ten sposób kolejnego błędu). Faktem jest jednak, iż to głównie programista wykrywa najwięcej błędów, w rezultacie (jedynie) głośnego odczytywania treści programu wobec uważnego audytorium — czyli w wyniku zastosowania techniki zgoła nieskomplikowanej, acz niewątpliwie użytecznej. Program analizowany jest pod kątem zgodności z tzw. listą kontrolną (checklist) powszechnie popełnianych błędów, tworzoną i aktualizowaną w następstwie kolejnych sesji testowych. Przykład takiej listy przedstawimy w dalszej części rozdziału. 2. Moderator jest odpowiedzialny za rzeczowość dyskusji oraz za to, by jej uczestnicy koncentrowali swą uwagę na wykrywaniu błędów, nie zaś na ich poprawianiu (poprawianiem błędów zajmuje się pro- gramista po zakończeniu sesji inspekcyjnej). Jeśli efektem sesji jest wykrycie dużej liczby błędów bądź wykryte zostają błędy wymagające znaczącej ingerencji w kod programu, mo- derator może zarządzić ponowną inspekcję po poprawieniu tych błędów przez programistę. W każdym przypadku wykryte błędy są analizowane, klasyfikowane i stanowią podstawę do aktualizacji listy kontrolnej, której ulepszona treść powinna przyczynić się do większej efektywności następnych sesji inspekcyjnych. Jak wcześniej stwierdziliśmy, celem inspekcji kodu jest zwykle wy- krywanie błędów, nie ich poprawianie; w przypadku jednakże błę- dów oczywistych, wymagających nieznacznych zmian w kodzie, do- konuje się niekiedy ich „kolektywnego” poprawiania na bieżąco w czasie sesji. Ubocznym efektem takiego postępowania jest zwróce- nie szczególnej uwagi zespołu na pewne wybrane obszary projektu — w czasie dyskusji nad sposobem poprawienia drobnego błędu ktoś może mianowicie zauważyć inny błąd, związany z tym samym aspektem projektu, co w efekcie już po kilku minutach skoncentro- wanej dyskusji może doprowadzić do wykrycia innego, tym razem poważnego błędu. 4 4 S Z T U K A T E S T O W A N I A O P R O G R A M O W A N I A Czas i miejsce sesji inspekcyjnych powinny być tak wybierane, by sesje te mogły odbywać się bez jakichkolwiek zakłóceń. Optymalny czas sesji zawiera się w granicach 90 – 120 minut; ze względu na dość duży wysiłek intelektualny uczestników sesji nadmierne jej przedłu- żanie z konieczności skutkować musi spadkiem produktywności. Średnia produktywność sesji inspekcyjnej oscyluje wokół 150 anali- zowanych instrukcji w ciągu godziny, tak więc inspekcja dużych pro- gramów powinna być podzielona między kilka sesji, w ramach któ- rych analizuje się poszczególne moduły programu (lub powiązane grupy modułów). Nie należy zapominać, iż warunkiem powodzenia sesji inspek- cyjnej jest odpowiednie nastawienie jej uczestników oraz odpowied- nia atmosfera w zespole. Jeśli programista postrzega inspekcję swego programu jako atak na swe kwalifikacje, przyjmuje postawę obron- ną, z oczywistych względów stawiającą pod znakiem zapytania efek- tywność samej inspekcji. Tymczasem powinien on zdawać sobie sprawę, że ostatecznym celem inspekcji jest przecież ulepszanie jego dzieła drogą eliminowania tkwiących w nim z konieczności błędów. Z tego też względu zalecane jest, by wyniki sesji inspekcyjnych pozo- stawały poufną sprawą zespołów testowych; gdyby z wyników tych chcieli zrobić jakiś użytek np. menedżerowie, ryzykują oni pojawie- nie się wspomnianych postaw defensywnych. Mimo iż głównym celem inspekcji programu jest wykrywanie błędów tkwiących w programach, to zwykle ma ona także kilka po- żytecznych efektów ubocznych. Programista będący członkiem ze- społu inspekcyjnego może na przykład na bieżąco weryfikować po- szczególne elementy swego stylu programowania, swój repertuar technik programistycznych, swe preferencje wyboru algorytmów itp. Inni członkowie zespołu mogą wzbogacać swe doświadczenia w za- kresie możliwych rodzajów błędów, wykrywanych w rzeczywistych pro- gramach. Co więcej, sesje inspekcyjne są znakomitym środkiem do wczesnego wykrywania obszarów kodu szczególnie podatnych na błędy (vide reguła nr 9 testowania programów w poprzednim rozdzia- le), dzięki czemu obszarom tym poświęcić można szczególną uwagę podczas testowania maszynowego. I N S P E K C J A P R O G R A M Ó W , W Ę D R Ó W K A P O K O D Z I E . . . 4 5 Lista kontrolna błędów programistycznych na użytek inspekcji kodu Istotną częścią procesu inspekcji jest lista kontrolna najczęściej po- pełnianych błędów programistycznych (error checklist). Niestety, treść większości takich list bądź to koncentruje się na zagadnieniach styli- stycznych zamiast merytorycznych („czy komentarze są treściwe i ade- kwatne?”, „czy bloki kodu, warianty instrukcji if i zagnieżdżane cia- ła pętli są poprawnie akapitowane?”), bądź też same opisy błędów formułowane są dość mgliście („czy kod należycie spełnia wymaga- nia projektowe?”). Prezentowana poniżej przykładowa lista kontro- lna jest efektem wieloletnich studiów nad najczęściej popełnianymi błędami programistycznymi. Jest ona w dużym stopniu niezależna od konkretnego języka programowania — wymienione na niej błędy wystąpić mogą niemal w każdym języku. Pouczającym dla Czytelni- ków ćwiczeniem może być wzbogacenie jej o błędy charakterystycz- ne dla niektórych tylko języków programowania oraz o błędy wy- krywane w ramach własnych sesji inspekcyjnych. Błędy w odwołaniach do danych 1. 2. 3. Czy zmienna, do której następuje odwołanie, jest zainicjowana, czy też ma przypadkową wartość? Niezainicjowane zmienne są prawdopodobnie najczęstszą przyczyną niewłaściwego funkcjonowania programów, a przyczyny braku inicjowania mogą być rozmaite. Dla każdej danej (zmiennej, elementu tablicy, pola w strukturze), do której w danym miejscu kodu następuje odwołanie, należy podjąć próbę przeprowadzenia nieformalnego „dowodu”, iż w momencie tego odwołania ma ona określoną wartość. Czy w odwołaniach do elementów tablic wartości indeksów mieszczą się w zadeklarowanych granicach? Czy w odwołaniach do elementów tablicy indeksy mają wartości całkowite? Niecałkowita wartość indeksu nie jest błędem w niektórych językach programowania, mimo to zawsze wygląda podejrzanie, a jej zamierzone stosowanie nie jest bezpieczną praktyką. 4 6 S Z T U K A T E S T O W A N I A O P R O G R A M O W A N I A 4. 5. 6. Czy obszar pamięci, wskazywany przez wskaźnik, nadal pozostaje przydzielony? Zwolnienie obszaru pamięci wskazywanego przez jakiś wskaźnik czyni ten ostatni tzw. wiszącym wskaźnikiem (dangling pointer); błąd wiszącego wskaźnika występuje zawsze wtedy, gdy sam wskaźnik jest obiektem o dłuższym czasie życia niż obiekt przezeń wskazywany. Przykładem takiej sytuacji jest przypisanie zmiennej globalnej (lub parametrowi wyjściowemu procedury) wskazania na tymczasową zmienną lokalną procedury; po zakończeniu realizacji takiej procedury jej zmienne lokalne przestają istnieć, lecz wspomniane wskaźniki zachowują swą wartość, stając się wskaźnikami wiszącymi. Podobnie jak w punkcie 1., dla każdego wskaźnika, do którego następuje odwołanie, należy spróbować nieformalnie dowieść, że w momencie tego odwołania nie jest on wskaźnikiem wiszącym. Czy to samo miejsce w pamięci zajmowane jest przez dwie lub większą liczbę zmiennych o odmiennych atrybutach? Współdzielenie pamięci przez różne zmienne ma miejsce w przypadku zastosowania np. dyrektywy EQUIVALENCE w języku FORTRAN czy klauzuli REDEFINES w języku COBOL1. Jeśli na przykład w fortranowskim programie dyrektywa EQUIVALENCE utożsamia zmienną rzeczywistą A ze zmienną całkowitą B, to przypisanie jakiejkolwiek wartości zmiennej A powoduje automatycznie, że zmienna B zyskuje wartość przypadkową, zależną od konkretnej implementacji (odwołanie do zmiennej B spowoduje zinterpretowanie jako liczby całkowitej wzorca bitowego odzwierciedlającego liczbę rzeczywistą). Czy atrybut wartości przypisywanej zmiennej zgodny jest z deklarowanym atrybutem tej zmiennej? Niezgodność taka może wystąpić np. w języku C++ lub COBOL w sytuacji, gdy zmiennej strukturalnej przypisywany jest odczytany z pliku rekord o strukturze niezgodnej ze strukturą tej zmiennej2. 1 W Turbo Pascalu i Delphi zadanie to spełnia klauzula absolute — przyp. tłum. 2 W Turbo Pascalu i Delphi może się tak zdarzyć w przypadku wczytywania danych z plików amorficznych za pomocą procedury BlockRead — przyp. tłum. (cid:10) I N S P E K C J A P R O G R A M Ó W , W Ę D R Ó W K A P O K O D Z I E . . . 4 7 7. 8. Czy w programie nie występują jawne lub wtórne błędy adresowania? Jeżeli na przykład w konkretnej implementacji jakiegoś języka programowania logiczne jednostki alokacji pamięci są mniejsze od jednostek fizycznie adresowalnych przez maszynę, błędy adresowania są bardzo prawdopodobne. Przykładem takiej sytuacji jest alokowanie łańcuchów bitowych niewyrównanych na granicach bajtu w maszynie o adresowaniu bajtowym; jeśli w programie obliczany jest adres łańcucha bitowego i następnie adres ten przypisywany jest wskaźnikowi, to w przypadku niewyrównania wspomnianego łańcucha na granicy bajtu odwołanie się do rzeczonego wskaźnika da efekty inne od oczekiwanych3. Podobna sytuacja wystąpić może w przypadku przekazywania niewyrównanego łańcucha bitowego jako parametru procedury. Czy obszar pamięci wskazywany przez wskaźnik (lub referencję) ma właściwe atrybuty? W języku C++ niezgodność taka może wystąpić, gdy wskaźnik i wskazywany przez niego obszar różnią się od siebie deklaracją4. Ani w Turbo Pascalu, ani w Delphi nie jest możliwe deklarowanie ani alokowanie danych niewyrównanych do granicy bajtu — przyp. tłum. Oto przykład takiej sytuacji w Turbo Pascalu: Type PRecord1 = ^TRecord1; TRecord1 = record NrId: Longint; Nazwisko: String[30]; Imię: string[15] end; Precord2 = ^TRecord2; TRecord2 = record NrRef: integer; Stanowisko: String[35]; Lokal: string[8] end; 3 4 var X1 : Precord1; X2 : Precord2; P: Pointer; ... New(X1); P := X1; ... X2 := P; Writeln(X2^.NrRef); — przyp. tłum. (cid:10) 4 8 S Z T U K A T E S T O W A N I A O P R O G R A M O W A N I A 9. 10. 11. Czy dana, do której odwołuje się kilka procedur, jest „widziana” (pod względem struktury) w identyczny sposób przez każdą z tych procedur? Czy w indeksowaniu elementów tablic lub poszczególnych znaków łańcucha nie popełniono błędu „pomyłki o jeden”?5 W językach obiektowych — czy w implementacji klasy pochodnej uwzględniono wszystkie wymogi wynikające z dziedziczenia klas?6 Błędy w deklaracjach danych 1. Czy wszystkie używane zmienne zadeklarowane zostały w sposób jawny? W niektórych językach (np. w FORTRAN-ie) nie ma wymogu deklarowania zmiennych, lecz brak jawnej deklaracji zmiennej może być przyczyną poważnych kłopotów. Jeśli na przykład parametr formalny (nazwijmy go A) podprogramu fortranowskiego miał być w zamierzeniu tablicą, lecz pominięto jego deklarację (np. w postaci dyrektywy DIMENSION A(10)), wszelkie odwołania do elementów tej tablicy (np. C = A(I)) zinterpretowane zostaną jako odwołania do funkcji reprezentowanej przez parametr A. W efekcie podjęta zostanie próba wykonania… zawartości tablicy (przekazanej jako parametr aktualny), postrzeganej jako kod programu. W językach programowania dopuszczających zagnieżdżanie deklaracji procedur brak deklaracji zmiennej używanej 5 Błąd „pomyłki o jeden” (off-by-one error) polega na „rozminięciu się” o 1 faktycznego wyniku z prawidłowym. Przykładem takiego błędu jest niepoprawna odpowiedź na pytanie, ile słupów trzeba postawić na dziesięciokilometrowej linii energetycznej, jeśli odległość między słupami wynosi 50 metrów? Udzielana często nieprzemyślana odpowiedź (200) różni się od poprawnej (201) o jeden — przyp. tłum. 6 W C++ i Delphi jednym z takich wymogów jest zaimplementowanie wszystkich metod abstrakcyjnych klasy macierzystej (chyba że nie chcemy tworzyć instancji obiektu). Również często spotykanym w Delphi uchybieniem takiemu wymogowi jest pomylenie klauzul virtual i override — przyp. tłum. (cid:10) I N S P E K C J A P R O G R A M Ó W , W Ę D R Ó W K A P O K O D Z I E . . . 4 9 2. 3. 4. 5. w ciele procedury powoduje zinterpretowanie jej jako zmiennej globalnej, nie zawsze zgodnie z intencją programisty7. Jeśli atrybuty zmiennej nie zostały jawnie wymienione w jej deklaracji, to czy domyślne ustalenia atrybutów zostały właściwie zrozumiane przez programistę? Błędne założenia co do domyślnych atrybutów w języku Java są częstym źródłem niespodzianek. Czy inicjowanie zmiennej w jej deklaracji jest prawidłowe? W wielu językach inicjowanie deklarowanych tablic i łańcuchów jest skomplikowane i podatne na błędy. Czy każdej zmiennej przypisano właściwy typ i rozmiar? Czy sposób inicjowania zmiennej jest spójny z rodzajem zajmowanej przez nią pamięci? Przykładowo w języku FORTRAN, jeżeli jakaś zmienna ma być inicjowana przy każdym wejściu do podprogramu, to inicjowanie 7 Oto przykład w Turbo Pascalu — składniowo poprawny, lecz w procedurze B zapomniano zadeklarować zmienną lokalną i: procedure A; const LL = 10; type LLArr = array [ 1..LL ] of integer; var i: integer; M: LLArr; N: array[1..LL] of LLArr; procedure B (var X: array of integer; var K:integer); begin {B} i := Low(X); while (i = High(X)) and (X[i] = 0) do inc(i); .... end; {B} begin {A} ... for i := Low(M) to High(M) do begin B(N[i], M[i]) end; .... end {A} — przyp. tłum. (cid:10) 5 0 S Z T U K A T E S T O W A N I A O P R O G R A M O W A N I A 6. to powinno odbywać się w instrukcji przypisania, a nie w dyrektywie DATA8. Czy w programie występują zmienne o podobnych nazwach (np. VOLT i VOLTS)? Nie musi to być błąd, lecz sytuacja taka może być wynikiem pomyłki programisty9. Błędy obliczeniowe 1. 2. Czy w programie prowadzone są jakieś obliczenia na zmiennych nienumerycznych? Czy w programie występuje mieszanie typów zmiennych w wyrażeniach, na przykład mieszanie wartości całkowitych i zmiennopozycyjnych? Jeżeli tak, należy upewnić się, że określone przez semantykę języka reguły konwersji typów danych zostały właściwie zrozumiane. Oto fragment kodu w języku Java prezentujący zaokrąglanie niezgodne z oczekiwanym: int x = 1; int y = 2; int z = 0; z = x/y; System.out.println( z = + z); W wyniku wykonania powyższego kodu wypisana 3. zostanie wartość 0. Czy w jakimś obliczeniu biorą udział dwie zmienne tego samego typu, lecz różnej długości? 8 9 W Turbo Pascalu odpowiednikiem fortranowskiej dyrektywy DATA są tzw. stałe typowane, na przykład: const MonthLenghts : array[1..12] of byte = (31,28,31,30,31,30,31,31,30,31,30,31); — przyp. tłum. Podobieństwo nazw może mieć inną jeszcze konsekwencję: otóż wiele kompilatorów uwzględnia jedynie określoną liczbę początkowych znaków identyfikatora; przykładowo niektóre wersje języka FORTRAN rozróżniają tylko sześć pierwszych znaków nazwy, tak więc np. identyfikatory IPOWERX1, IPOWERX2, IPOWERY1 i IPOWERY2 orz IPOWER oznaczają wówczas tę samą zmienną! W Turbo Pascalu znacząca część identyfikatora także jest ograniczona — choć znacznie dłuższa, bo kompilator rozróżnia 63 początkowe znaki — przyp. tłum. (cid:10) I N S P E K C J A P R O G R A M Ó W , W Ę D R Ó W K A P O K O D Z I E . . . 5 1 4. 5. 6. 7. 8. 9. 10. Czy w którymś obliczeniu typ zmiennej wynikowej ma „węższy” zakres niż typ przypisywanego wyniku? Czy w którymś obliczeniu może wystąpić nadmiar lub niedomiar? Czy jest możliwe, by mimo poprawnej wartości ostatecznego wyniku wyniki pośrednie przekraczały zakres dozwolony w danym języku? Czy jest możliwe, by w którejś operacji dzielenia dzielnik miał wartość zerową? Jeżeli arytmetyka zmiennopozycyjna komputera zrealizowana jest w układzie dwójkowym, to czy program wolny jest od lawinowo kumulujących się błędów zaokrągleń z tego tytułu? W takim komputerze wynik obliczenia10 10 * 0.1 może nie być dokładnie równy 1. Czy możliwe jest, że dana zmienna ma wartość wykraczającą poza zakres wynikający z jej roli w programie? Jeśli na przykład jakaś zmienna rzeczywista reprezentuje prawdopodobieństwo zdarzenia, czy możliwe jest, że przypisuje się jej wartość ujemną albo większą od 1? Czy w konstrukcji wyrażenia zawierającego kilka operatorów należycie zrozumiane zostały reguły pierwszeństwa operatorów obowiązujące w danym języku? Czy w programie występują przypadki niewłaściwego użycia arytmetyki całkowitoliczbowej? Jeżeli na przykład i jest zmienną całkowitą, czy warunek 2*i/2 == 1 prawdziwy jest zarówno dla parzystej, jak i nieparzystej wartości i? (Odpowiedź na to pytanie zależna jest od tego, które z działań — mnożenie czy dzielenie — wykonane zostanie najpierw). Błędy porównywania 1. Czy w programie występują porównania zmiennych różnych typów, na przykład porównanie łańcucha ze wskaźnikiem, datą lub liczbą? Jeśli tak, to czy reguły 10 Ułamek zapisywany w układzie dziesiętnym jako 0,1 w pozycyjnym układzie dwójkowym jest nieskończonym ułamkiem okresowym 0,000110011001100110011.. — przyp. tłum. (cid:10) 5 2 S Z T U K A T E S T O W A N I A O P R O G R A M O W A N I A 2. 3. 4. 5. 6. 7. konwersji między typami danych zostały należycie zrozumiane? Czy w programie występują porównania zmiennych o różnych długościach? Jak traktowane są one w danym języku programowania?11 Czy wybrano właściwy operator porównania? Programiści często błędnie interpretują warunki „co najwyżej”, „co najmniej”, „większy niż…”, „nie większy niż…”, „mniejszy lub równy” itp. Czy składnia wyrażenia boolowskiego jest zgodna z intencją programisty? Czy właściwie zrozumiał on znaczenie i reguły pierwszeństwa operatorów and, or, not itp. Czy argumenty operatorów boolowskich są wyrażeniami boolowskimi? Czy kombinacja operatorów boolowskich i operatorów porównania jest właściwa? Oto kilka przykładów błędów tego rodzaju. Warunku, iż wartość i zawiera się pomiędzy 2 a 10, nie można zapisać jako 2 i 10, lecz należy go zapisać w postaci (2 i) (i 10). Badanie, czy i większe jest od x lub y, nie może być zapisane jako i x||y, lecz trzeba je zapisać w postaci (i x) || (i y). Podobnie wyrażenie if (a==b==c) nie jest poprawnym testem na równość zmiennych a, b i c, zaś matematyczna relacja x y z musi być zapisana w postaci (x y) (y z). Czy w kodzie programu, realizowanego na maszynie o architekturze binarnej, występują porównania liczb ułamkowych lub zmiennopozycyjnych? Mogą być one źródłem nieoczekiwanych błędów, bowiem niektórych skończonych ułamków dziesiętnych nie da się dokładnie zapisać w reprezentacji dwójkowej. Czy przy konstrukcji złożonego wyrażenia boolowskiego należycie zrozumiano zasady pierwszeństwa operatorów boolowskich, obowiązujące w danym języku? Przykładowo, która operacja — alternatywa czy koniunkcja — wykonana 11 W popularnym niegdyś języku CLIPPER łańcuchy ALA i ALABASTER mogły (w pewnych warunkach — ustawienie SET EXACT OFF) zostać uznane za równe, bowiem porównywanie kończyło się w momencie wyczerpania krótszego łańcucha. — przyp. tłum. (cid:10) I N S P E K C J A P R O G R A M Ó W , W Ę D R Ó W K A P O K O D Z I E . . . 5 3 8. zostanie najpierw w wyrażeniu if((a==2 (b==2) || (c==3))? Czy sposób wartościowania wyrażeń boolowskich (wartościowanie częściowe albo kompletne) może mieć wpływ na poprawność programu? W wyrażeniu if ((y==0) || (x/y) z) w sytuacji, gdy y równe jest zero, ostateczny wynik znany jest już po obliczeniu pierwszego członu. Obliczanie drugiego członu12 nie jest już konieczne, lecz jeśli mimo to zostanie wykonane, wystąpi błąd dzielenia przez 0. Błędy przepływu sterowania 1. Jeżeli w programie występuje rozgałęzienie wielokierunkowe, na przykład „liczone GO TO” w języku FORTRAN, czy wartość zmiennej sterującej może przekroczyć liczbę wariantów skoku? Przykładowo, czy w instrukcji GO TO (200, 300, 400), K 2. 3. 4. zmienna K może mieć wartość inną niż 1, 2 lub 3? Czy każda pętla w programie ostatecznie się kończy? Spróbuj przeprowadzić nieformalny dowód tego dla każdej z nich. Czy każda procedura, funkcja, podprogram i sam program kończą się ostatecznie? Czy możliwe jest, że któraś pętla dla pewnych danych wejściowych nie wykona się ani razu? Jeśli tak, to czy jest to efekt zamierzony, czy przeoczenie? Przykładowo co stanie się w poniższym fragmencie for (i==x ; i = z ; i++) { ... } 12 W Turbo Pascalu i Delphi możliwe jest sterowanie sposobem wartościowania wyrażeń boolowskich za pomocą opcji kompilacji $B: gdy opcja ta jest włączona ($B+), każde wyrażenie boolowskie obliczane jest w sposób kompletny. Wyłączenie opcji powoduje zakończenie obliczeń wtedy, gdy wartość wyrażenia staje się przesądzona — przyp. tłum. (cid:10) 5 4 S Z T U K A T E S T O W A N I A O P R O G R A M O W A N I A while (NOTFOUND) { ... } 5. jeśli zmienna NOTFOUND będzie miała początkową wartość false lub x będzie większe niż z? Co stanie się w przypadku pętli sterowanej zarówno przez iterację, jak i warunek boolowski (na przykład pętli realizującej przeszukiwanie tablicy), gdy warunek boolowski nie będzie nigdy spełniony? Przykładowo jak zachowa się pętla DO I=1 to TABLESIZE WHILE (NOTFOUND) 6. gdy NOTFOUND nigdy nie osiągnie wartości false? Czy program wolny jest od błędów „pomyłki o jeden”? Czy żadna z pętli nie wykonuje zbyt mało lub zbyt wiele iteracji? Wspomniany błąd charakterystyczny jest dla pętli rozpoczynających się od zerowej wartości zmiennej sterującej, bowiem wartość 0 często zostaje przeoczona. W poniższej pętli: for (int i=0; i =10;i++) { System.out.println(i); } wypisanych zostanie 11, a nie 10 wartości. Poprawna pętla zliczająca do dziesięciu powinna wyglądać następująco: for (int i=0; i =9;i++) { System.out.println(i); } 7. 8. Jeżeli składnia języka umożliwia grupowanie instrukcji, np. w bloki ujęte w nawiasy {...} czy też w pętle do while, to czy grupowanie to jest prawidłowe? Czy każdemu otwierającemu nawiasowi { odpowiada nawias zamykający }? Czy każde ciało pętli while jest prawidłowo ograniczone przez frazy while i do? Większość współczesnych kompilatorów automatycznie wykrywa tego typu nieprawidłowości. Czy w każdej instrukcji warunkowej uwzględniono wszystkie możliwe sytuacje? Jeżeli na przykład przewidziano konkretne działania w sytuacjach, gdy testowana zmienna ma wartość 1, 2 lub 3, to czy można być pewnym, że nie może ona przyjmować żadnych innych wartości? I N S P E K C J A P R O G R A M Ó W , W Ę D R Ó W K A P O K O D Z I E . . . 5 5 Błędy interfejsu 1. 2. 3. 4. 5. 6. 7. 8. Czy liczba parametrów aktualnych w wywołaniach modułu (procedury, funkcji, podprogramu) równa jest13 liczbie deklarowanych przez niego parametrów formalnych? Czy atrybut (typ i rozmiar) każdego parametru aktualnego zgodny jest14 z atrybutem odpowiadającego mu parametru formalnego? Czy jednostka, w jakiej wyrażana jest wartość parametru aktualnego, zgodna jest z jednostką założoną przy deklarowaniu parametru formalnego? Czy na przykład do funkcji, której parametr jest z założenia wielkością kąta mierzonego w stopniach, przekazywana jest wielkość kąta mierzona w radianach? Czy liczba parametrów w dynamicznym wywołaniu modułu jest równa liczbie parametrów spodziewanych w przypadku tego modułu? Czy atrybut każdego parametru w dynamicznym wywołaniu modułu zgodny jest z atrybutem oczekiwanym dla tego parametru przez wywoływany moduł? Czy jednostki, w których mierzone są wartości parametrów przekazywanych w dynamicznym wywołaniu modułu, zgodne są z jednostkami oczekiwanymi przez ten moduł? Czy parametry w wywołaniach funkcji wbudowanych prawidłowe są co do liczby, atrybutów i kolejności? Czy — w przypadku klasy lub modułu mających kilka punktów wejścia — w którymś z tych punktów występują odwołania do parametrów, które nie zostały zainicjowane? Sytuacja taka występuje w poniższym programie (w języku PL/I) — w punkcie wejścia B zmienna X nie ma określonej wartości. 13 14 W niektórych językach (m. in. w C/C++) możliwe jest deklarowanie modułów (funkcji) dopuszczających zmienną liczbę parametrów wywołania. W Delphi istnieje namiastka tego mechanizmu w postaci tablic array of const — przyp. tłum. W niektórych językach (Delphi, Visual Basic, C++) typ zmiennej może przeobrażać się dynamicznie w czasie wykonywania programu — są tso tzw. zmienne wariantowe. Jeżeli parametr formalny deklarowany jest jako wariantowy, to parametr aktualny może mieć dowolny typ zgodny z typem wariantowym — przyp. tłum. (cid:10) 5 6 S Z T U K A T E S T O W A N I A O P R O G R A M O W A N I A A: PROCEDURE(W, X); W=X+1; RETURN B: ENTRY(Y,Z); Y=X+Z; END; 9. 10. 11. Czy wykonanie podprogramu powoduje zmianę parametru, który z założenia powinien pozostać niezmienny? Czy w przypadku użycia zmiennych globalnych są one „widziane” w identyczny sposób (pod względem definicji) przez wszystkie odwołujące się do nich moduły? Czy w wywołaniach podprogramów (procedur, funkcji) używane są stałe (w roli parametrów aktualnych)? W niektórych implementacjach języka FORTRAN wywołanie CALL SUB(J,3) może być niebezpieczne, jeżeli bowiem wykonanie podprogramu SUB zmienia wartość drugiego parametru, to może ulec zniszczeniu obszar pamięci, w którym program przechowuje stałą 3, w efekcie czego stała przestanie być stałą. Błędy wejścia-wyjścia 1. 2. 3. 4. 5. Czy atrybuty jawnie deklarowanych plików są prawidłowe? Czy atrybuty parametrów wywołania procedury OPEN są poprawne? Czy specyfikacja formatu wejścia-wyjścia zgodna jest z zestawem zmiennych (wyrażeń) w instrukcji wejścia-wyjścia powołującej się na ten format? W języku FORTRAN istnieje ścisła zależność między listą wejścia-wyjścia w instrukcjach READ i WRITE a instrukcjami FORMAT, na które instrukcje te się powołują? Czy dla programu dostępna jest wystarczająca ilość pamięci dla danych wczytywanych z plików? Czy każdy używany plik zostaje otwarty przed wykonaniem na nim operacji odczytu lub zapisu? I N S P E K C J A P R O G R A M Ó W , W Ę D R Ó W K A P O K O D Z I E . . . 5 7 6. 7. 8. 9. Czy każdy otwierany plik jest zamykany po użyciu? Czy wystąpienie końca pliku (eof) jest prawidłowo wykrywane i obsługiwane? Czy wyjątki i błędy wejścia-wyjścia są prawidłowo wykrywane i obsługiwane? Czy w tekstach drukowanych (wyświetlanych) przez program nie występują błędy literowe lub gramatyczne? Inne błędy 1. 2. 3. 4. 5. Czy w (tworzonym przez kompilator) listingu odwołań do obiektów (cross-reference listing) występują zmienne, do których nie ma odwołania lub do których występują tylko odwołania jednokrotne? Jednokrotne odwołanie do zmiennej może świadczyć o tym, iż w rzeczywistości jest to zniekształcona nazwa innej zmiennej. Jeśli kompilator tworzy listing atrybutów zmiennych, należy sprawdzić, czy którejś zmiennej nie został błędnie przypisany atrybut domyślny. Jeżeli w wyniku kompilacji generowane są komunikaty ostrzegawcze (warnings) lub informacyjne (hints, tips, infos), należy każdy z nich dokładnie przeanalizować. Komunikaty ostrzegawcze sygnalizują sytuacje, które kompilatorowi „wydają się” podejrzane i które mogą oznaczać rozminięcie się programisty z założeniami. Komunikaty informacyjne dotyczą natomiast rozmaitych aspektów kodu: niezadeklarowanych zmiennych, konstrukcji utrudniających lub uniemożliwiających optymalizację itd. Czy moduł (program) dokonuje dostatecznej kontroli poprawności danych wejściowych? Czy w programie pominięto jakąś funkcję? Powyższa lista kontrolna zestawiona została w skrócie w tabelach 3.1 i 3.2. 5 8 S Z T U K A T E S T O W A N I A O P R O G R A M O W A N I A Tabela 3.1. Lista kontrolna inspekcji programu, część pierwsza Odwołania do danych Obliczenia 1. Użycie niezainicjowanych zmiennych. 1. Obliczenia z udziałem zmiennych 2. Indeksy poza dopuszczalnym zakresem. 3. Niecałkowita wartość indeksu. 4. „Wiszące” wskaźniki i referencje. 5. Niezgodność atrybutów zmiennych współdzielących obszar pamięci. 6. Niezgodność atrybutów w strukturze lub rekordzie. 7. Obliczanie adresów danych niewyrównanych na granicy adresowania maszynowego. 8. Błędna struktura wskazywanego obszaru. 9. Niezgodność deklaracji struktury w procedurach. 10. Błąd „pomyłki o jeden” w indeksowaniu tablic lub łańcuchów. 11. Niespełnienie wymogów dziedziczenia klasy. nienumerycznych. 2. Obliczenia z udziałem „mieszanych” typów danych. 3. Obliczenia z udziałem zmiennych o zróżnicowanej długości. 4. Zakres typu zmiennej wynikowej niewystarczający do pomieszczenia wyniku obliczeń. 5. Nadmiar lub niedomiar pośrednich wyników obliczeń. 6. Dzielenie przez zero. 7. Błędy zaokrągleń wynikające z binarnej arytmetyki zmiennopozycyjnej. 8. Wartość zmiennej poza dopuszczalnym zakresem. 9. Niewłaściwe założenie co do pierwszeństwa operatorów. 10. Nieprawidłowe dzielenie zmiennych całkowitych. Deklaracje danych Porównania 1. Użycie niezadeklarowanej zmiennej. 1. Porównywanie niezgodnych zmiennych. 2. Błędne założenia co do ustawień 2. Porównywanie danych mieszanych domyślnych. typów. 3. Niepoprawna inicjacja tablic 3. Błędne operatory relacyjne. i łańcuchów. 4. Niepoprawność długości, typu i zakresu widoczności zmiennej. 5. Niezgodność sposobu inicjowania zmiennej z jej klasą pamięciową. 6. Zmienne o bardzo podobnych nazwach. 4. Błędne wyrażenia boolowskie. 5. Błędna kombinacja operatorów boolowskich i operatorów relacyjnych. 6. Porównywanie wartości ułamkowych lub zmiennopozycyjnych w binarnej arytmetyce zmiennopozycyjnej. 7. Niewłaściwe założenie co do pierwszeństwa operatorów (porównania i boolowskich). 8. Błędna specyfikacja wartościowania wyrażeń boolowskich (wartościowanie skrócone albo kompletne). I N S P E K C J A P R O G R A M Ó W , W Ę D R Ó W K A P O K O D Z I E . . . 5 9 Tabela 3.2. Lista kontrolna inspekcji programu, część druga Przepływ sterowania Wejście-wyjście 1. Niekompletne rozgałęzienia wielokierunkowe. 2. Niekończące się pętle. 3. Niekończący się program. 1. Niepoprawne atrybuty plików. 2. Niepoprawne instrukcje OPEN. 3. Niezgodność formatów z instrukcjami wejścia-wyjścia. 4. Pętle niewykonywane ani razu z powodu 4. Bufory zbyt małe dla błędnych warunków wejściowych. wczytywanych danych. 5. Błędne zakończenia pętli sterowanych 5. Próba odczytu lub zapisu z (do) dodatkowym warunkiem. nieotwartego pliku. 6. Błąd „pomyłki o jeden” w ustalaniu liczby 6. Niezamknięcie pliku po użyciu. iteracji pętli. 7. Niepoprawna obsługa sytuacji 7. Niedopasowane ograniczniki DO/END. końca pliku. 8. Nieuwzględnienie pewnych sytuacji 8. Niepoprawna obsługa błędów w wyrażeniu warunkowym. wejścia-wyjścia. 9. Błędy literowe i gramatyczne w drukowanych lub wyświetlanych komunikatach. Interfejs Inne 1. Brak odwołań do niektórych zmiennych (wykazywany na listingu odwołań tworzonym przez kompilator). 2. Błędne przyporządkowanie zmiennym domyślnych atrybutów. 3. Ostrzegawcze i (lub) informacyjne komunikaty kompilatora. 4. Niedostateczna kontrola poprawności danych wejściowych modułu. 5. Przeoczenie jakiejś funkcji programu. 1. Niezgodna liczba parametrów formalnych i aktualnych. 2. Niezgodność atrybutów parametrów formalnych i aktualnych. 3. Niezgodne jednostki miar w wartościach parametrów formalnych i aktualnych. 4. Niewłaściwa liczba parametrów dynamicznego wywołania modułu. 5. Nieprawidłowe atrybuty parametrów dynamicznego wywołania modułu. 6. Niezgodne jednostki miar w wartościach parametrów dynamicznego wywołania modułu. 7. Niewłaściwa liczba, kolejność lub atrybuty parametrów w wywołaniu funkcji wbudowanej. 8. Odwołania do parametrów niezainicjowanych w danym punkcie wejściowym. 9. Niespójne odwołania do zmiennych globalnych w poszczególnych modułach. 10. Stałe w roli parametrów aktualnych. 6 0 S Z T U K A T E S T O W A N I A O P R O G R A M O W A N I A Wędrówki po kodzie Idea „wędrówek po kodzie” (walkthrougs) zbliżona jest w swej istocie do inspekcji programu, bowiem podobnie jak ona sprowadza się do grupowego czytania kodu. Jej szczegółowa realizacja jest jednak nie- co inna, inne są też techniki wykrywania błędów. Podobnie jak inspekcja kodu, także wędrówki po kodzie odbywa- ją się w ramach godzinnego lub dwugodzinnego, nieprzerwanego spotkania. Zespół „wędrowców” liczy od trzech do pięciu osób: jedna z nich odgrywa rolę podobną do roli moderatora w procesie inspek- cji, druga (sekretarka) dokonuje rejestracji wykrytych błędów, trzecia jest natomiast testerem. Co do kwalifikacji członków zespołu zdania są podzielone: niewątpliwie pożądane jest, by był wśród nich pro- gramista, wskazana jest też obecność (1) wysoko kwalifikowanego programisty, (2) eksperta w zakresie konkretnego języka programo- wania, (3) programisty-nowicjusza, o świeżym i nieskażonym spojrze- niu na proces programowania, (4) osoby, która zajmuje się (będzie się zajmować) konserwacją programu, (5) uczestnika innego projektu i (6) innej osoby z zespołu realizującego projekt. Procedura wędrówek po kodzie rozpoczyna się podobnie jak in- spekcja: członkowie zespołu otrzymują z kilkudniowym wyprzedze- niem niezbędne materiały. Dalej jest już jednak całkiem inaczej, bo- wiem uczestnicy, zamiast wsłuchiwać się w narrację prowadzoną w kontekście listy kontrolnej, uskuteczniają swoistą „zabawę w kom- puter”. Osoba, której wyznaczono rolę testera, przybywa na zebranie uzbrojona w niewielki zbiór zapisanych na papierze przypadków te- stowych — każdy z nich zawiera reprezentatywny zestaw danych wejściowych i oczywiście oczekiwany wynik dla tego zestawu. Zespól przystępuje następnie do mentalnego wykonywania programu na podsta- wie jego kodu źródłowego, z użyciem wspomnianych przypadków testowych jako danych wejściowych. Stan programu po wykonaniu każdej instrukcji zapisywany jest na kartce papieru lub (co wygod- niejsze) na tablicy. Zważywszy na znikomą „moc obliczeniową” owego symulowa- nego komputera, nie ma wątpliwości co do tego, że wykorzystywane przypadki testowe powinny być proste na tyle, aby nie wymagały skomplikowanych obliczeń. Nie odgrywają one zresztą krytycznej roli w całym procesie wędrówki — każdy z nich stanowi raczej wy god- I N S P E K C J A P R O G R A M Ó W , W Ę D R Ó W K A P O K O D Z I E . . . 6 1 ny punkt startowy do symulowanego wykonywania kodu, podczas którego programista odpowiedzieć musi na szereg pytań (zadawa- nych przez innych członków zespołu) dotyczących przyjętych zało- żeń, szczegółowych rozwiązań w zakresie kodowania itp.; większość błędów wykrywana jest właśnie w wyniku takiej konwersacji, a nie w rezultacie ostatecznego porównania oczekiwanego wyniku z rze- czywiście otrzymanym. Podobnie jak w przypadku inspekcji kodu, tak i tym razem krytycz- ne znaczenie dla powodzenia całego przedsięwzięcia ma odpowied- nia atmosfera i nastawienie członków zespołu. Wszelkie komentarze powinny być ukierunkowane raczej na sam program niż na jego au- tora; innymi słowy, wykrywane w programie błędy nie powinny być uważane za przejaw słabości programisty, lecz raczej za pewien przy- rodzony atrybut samego procesu programowania. Wszelkie zagadnienia pokrewne związane z wędrowaniem po kodzie źródłowym programu zbliżone są do tych związanych z in- spekcją kodu. W szczególności wynikające z inspekcji pożyteczne efekty uboczne — jak identyfikacja sekcji szczególnie podatnych na błędy czy też rozmaite walory edukacyjne — pozostają w pełni aktu- alne także w procesie symulowanego wykonywania kodu. Kontrola przy biurku Kolejną techniką bezkomputerowego testowania kodu jest samodziel- na analiza kodu programu, stanowiąca połączenie jednoosobowej inspekcji z wędrówką po kodzie źródłowym, zwana potocznie „kon- trolą przy biurku” (desk checking). Osoba analizująca program weryfikuje go pod kątem obecności błędów figurujących na liście kontrolnej, jak również dokonuje symulacji jego wykonywania na podstawie wła- snoręcznie sporządzonych przypadków testowych. W większości sytuacji postępowanie takie jest stosunkowo mało produktywne, z oczywistego powodu: osobą analizującą program jest zazwyczaj jego autor, co — jak wykazaliśmy w rozdziale 2. — nie jest czynnikiem sprzyjającym powodzeniu testowania. Wynika stąd dość interesujący pomysł, by dwaj programiści dokonujący analizy własnych programów po prostu wymienili się tymi programami; pomysł ten nie usuwa jednak kolejnego mankamentu, jakim jest 6 2 S Z T U K A T E S T O W A N I A O P R O G R A M O W A N I A brak współzawodnictwa charakterystycznego dla pracy zespołowej — każdy uczestnik inspekcji czy wędrowania po kodzie ma bowiem ambicję wykrycia jak największej liczby błędów. Samotna analiza pozbawiona jest tego efektu synergii i jakkolwiek jest ona lepsza niż zupełna bezczynność (na polu testowania programu), to jednak jest znacznie mniej produktywna w porównaniu z wędrówką po kodzie czy jego inspekcją. Wzajemna ocena Ostatnia z technik bezkomputerowego wykorzystywania kodu progra- mu, którą chcemy tu omówić, nie jest związana z testowaniem progra- mów — jej celem nie jest wykrywanie błędów. Wspominamy o niej w tym miejscu dlatego, iż bezpośrednio związana jest z czytaniem kodu źródłowego. Celem tego czytania jest ocena (anonimowego) progra- mu pod względem ogólnej jakości, łatwości konserwacji, możliwości rozbudowy, użyteczności, czytelności itp.; te cechy programu sta- nowią następnie podstawę do oceny jego autora jako programisty. Administrator procesu, którym jest zwykle doświadczony pro- gramista, wybiera od 6 do 20 uczestników (6 stanowi absolutne mi- nimum ze względu na zachowanie anonimowości). Wszyscy uczest- nicy powinni mieć zbliżone kwalifikacje i profil programistyczny — nie zaleca się na przykład łączenia internetowych programistów ko- rzystających z języka Java z programistami systemowymi wykorzy- stującymi głównie język asemblera. Każdy uczestnik proszony jest następnie o dostarczenie administratorowi dwóch własnych pro- gramów: najlepszego i najgorszego (wedle własnej oceny). Administrator dokonuje następnie rozprowadzenia — w sposób losowy — otrzymanych programów wśród uczestników sesji. Każdy z uczestników otrzymuje cztery (anonimowe) programy; dwa z nich należą do kategorii „najlepszy” (wedle samooceny autora), a dwa pozo- stałe do kategorii „najgorszy”, lecz osoba oceniająca nie zna przypo- rządkowania ocenianych przez siebie programów do poszczególnych kategorii. Osoba oceniająca ma następnie 30 minut na analizę wszyst- kich czterech programów, po czym powinna sklasyfikować każdy z nich według poniższych kryteriów, wartościując każde kryterium w skali od 1 do 7 (1 oznacza definitywne „tak”, 7 — definitywne „nie”): I N S P E K C J A P R O G R A M Ó W , W Ę D R Ó W K A P O K O D Z I E . . . 6 3 Czy program jest łatwy do zrozumienia? Czy wysokopoziomowe aspekty projektu są sensowne ♦ ♦ i zauważalne? Czy niskopoziomowe aspekty projektu są sensowne ♦ i zauważalne? Czy modyfikacja programu byłaby zadaniem łatwym ♦ dla osoby oceniającej? Czy osoba oceniająca byłaby dumna ze stworzenia takiego ♦ programu? Osoba oceniająca proszona jest także o inne komentarze i sugestie związane z programem, możliwościami jego ulepszeń itd. Po zakończeniu sesji każdy z uczestników otrzymuje formularz z oceną dostarczonych przez siebie programów — oceną zarówno sumaryczną, jak i ocenami wystawionymi przez poszczególnych oceniających (ci ostatni nadal pozostają dla autora programów ano- nimowi). Autor programów otrzymuje także informację o względnej pozycji swych programów w ogólnym rankingu (pod kątem po- szczególnych kryteriów), jak również porównanie własnej oceny in- nych programów z oceną własnych programów przez innych uczest- ników. W efekcie każdy uczestnik dysponuje informacją pozwalającą mu wyciągnąć odpowiednie wnioski odnośnie własnych kwalifikacji programistycznych. Ze względu na prostotę opisany proces da się ła- two zrealizować zarówno w szkolnej klasie, jak i w warunkach prze- mysłowych. Podsumowanie Niniejszy rozdział poświęcony jest testowaniu programów bez użycia komputera — które przez programistów wciąż nie jest należycie do- ceniane. Wielu z nich skłania się ku opinii, że program stworzony jest do wykonania przez maszynę i za pomocą tejże maszyny powi- nien być testowany. Założenie to jest z gruntu błędne, bowiem pro- gram, jako twór myśli ludzkiej, nadaje się także do analizy bezkom- puterowej, w ramach której wykrywanie błędów może być równie efektywne, jak w procesie testowania maszynowego (a niekiedy nawet bardziej). Integralnym elementem realizacji projektu informatycznego 6 4 S Z T U K A T E S T O W A N I A O P R O G R A M O W A N I A powinny być następujące techniki bezkomputerowego, „ludzkiego” testowania kodu: Inspekcja z wykorzystaniem listy kontrolnej. Wędrówka po kodzie, czyli grupowa „zabawa w komputer” ♦ ♦ polegająca na symulowanym wykonywaniu kodu źródłowego. Samodzielna analiza kodu „przy biurku”. Wzajemna ocena umiejętności programistycznych ♦ ♦ w ramach zespołu.
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Sztuka testowania oprogramowania
Autor:
, , ,

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: