07 września 2019, 22:19
Rozdział 6 Analiza kodu
W TYM ROZDZIALE Statyczne testowanie metodami szklanej skrzynki: badanie projektu konstrukcji i kodu Formalne przeglądy Standardy i reguły programowania Lista kontrolna do przeglądów kodu
Testowanie oprogramowania nie ogranicza się do tego, by traktować specyfikacje lub program jak „czarną skrzynkę”, jak to opisne zostalo w rozdziale 4-ym „Badanie specyfikacji” oraz w rozdziale 5-ym „Test z klapkami na oczach”. Znając trochę programowanie, nawet niewiele, można testować bezpośrednio projekt konstrukcji systemu oraz kod źródłowy.
W wielu branżach te metoda weryfikacji jest o wiele mniej powszechna niż testowanie metodami czarnej skrzynki. Tam, gdzie wytwarza się oprogramowanie dla zastosowań wojskowych, finansowcyh, kontroli procesów przemysłowych oraz dla zastosowań medycznych – albo jeśli ma się szczęście pracować w organizacji stosującej zdyscyplinowane metody wytwarzania - weryfikacja produktu na poziomie projektu oraz kodu jest powszechna.
Ten rozdział jest wprowadzeniem do podstaw weryfikacji projektu konstrukcji i kodu źródłowego. Nie jest to zwykle zadanie dla początkującego testera, ale przypuszczalnie – mając pewne umiejętności w programowaniu – tester zetknie się z tą dziedziną1.
Najważniejsze punkty w tym rozdziale to: 86.Zalety statycznego testu metodami szklanej skrzynki 87.Różne rodzaje statycznych przeglądów metodą szklanej skrzynki 88.Standardy i reguły kodowania 89.Ogólne metody inspekcji kodu w poszukiwaniu błędów Statyczne testowanie metodami szklanej skrzynki: badanie projektu konstrukcji i kodu
Autor 1 Autor wychodzi z założenia, że typowy tester nie jest wykształconym programistą. Oczywiście, nie musi tak być (przyp. tłumacza).
Przypomnijmy sobie definicje testowania statycznego i testowania metodami szklanej skrzynki z rozdziału 4-ego. Testowanie statyczne odnosie się do testowania czegoś co nie jest działającym kodem – do badania i inspekcji. Testowanie metodami szklanej skrzynki (albo „białej skrzynki”) oznacza, że ma się dostęp do wnętrza konstrukcji, do kodu programu.
Tak więc statyczne testowanie metodami szklanej skrzynki jest procesem starannego i metodycznego przeglądu projektu konstrukcji, architektury lub kodu źródłowego w celu znalezienia błędów bez uruchamiania programu. Czasami używa się też nazwy analiza strukturalna.
Motywy stosowania statycznego testu metodami szklanej skrzynki są dwa: znajdować błędy jak najwcześniej oraz znajdować błędy które byłoby trudno zidentyfikować i zlokalizować przy pomocy dynamicznego testowania metodami czarnej skrzynki. Im bardziej osoby dokonujące przeglądów są niezależne od zespołu wytwarzającego kod, tym lepiej, zwłaszcza jeśli znalizy dokonuje się na niskim poziomie i wcześnie w cyklu wytwarzania.
Dodatkowym zyskiem z przeprowadzania statycznego testu metodami szklanej skrzynki jest to, że w jego trakcie zespół testerów często znajduje wiele pomysłów, które daje się potem zastosować do testowania dynamicznego. Nawet nie wnikając w zawiłe szczegóły kodu, uczestnictwo w przeglądach pozwala zidentyfikować obszary programu które są zawiłe i gdzie często pojawiają się błędy.
Zespoły projektowe różnie dzielą się odpowiedzialnością za statyczne testowanie metodami szklanej skrzynki. W niektórych zespołach odpowiedzialność za zorganizowanie przeglądów spoczywa na programistach, którzy zapraszają na nie testerów w roli niezależnych obserwatorów. W innych zespołach odpowiedzialność spoczywa na testerach, którzy zapraszają programistów na przeglądy. Każde z tych podejść może działać dobrze. Zespół projektowy ma prawo wybrać to, co mu najlepiej odpowiada.
Statyczny test metodami szklanej skrzynki ma jedną wadę – nie zawsze się go przeprowadza. Wiele zespołów uległo przesądom, że ta technika jest zbyt czasochłonna, zbyt kosztowna i niezbyt produktywna. Wszystko to jest nieprawdą – w porównaniu z kosztami testowania, znajdowania niektórych i pomijania wielu błędów na samym końcu projektów. Kłopot w tym, że główne zadanie programisty wiele osób rozumie jako pisanie linijek kodu i każde zadanie, które zmniejsza tak rozumianą efektywność wydaje się spowalniać cały proces powstawania oprogramowania.
Na szczęście, czasy się zmieniają. Coraz więcej przedsiębiorstw zdaje sobie sprawę z zysków płynących z wczesnego testowania i zatrudnia oraz szkoli swoich programistów i testerów, aby wykonywali testowanie metodami szklanej skrzynki. Nie jest to ścisła matematyka (o ile ktoś nie testuje implementacji algorytmów matematycznych), ale żeby zacząć ją stosować przydaje się znajomość kilku podstawowych technik. Jeśli kogoś interesuje pójście jeszcze dalej, możliwości są olbrzymie. Formalne przeglądy
Przegląd formalny to proces, który steruje statycznym testowaniem metodami szklanej skrzynki. Przegląd formalny może mieć rozmaite formy – począwszy od prostego spotkania między dwoma programistami aż po szczegółową, rygorystyczną inspekcję kodu1.
Cztery elementy wyróżniają przeglądy formalne: 90.Identyfikacja problemów. Celem przeglądów jest znalezienie błędów – nie tylko tego, co jest zrealizowane niepoprawnie, ale również tego, czego brakuje. Krytykę kieruje się na kod (przedmiot przeglądu), a nie na osobę autora. Uczestnicy nie powinni traktować krytyki osobiście. Poczucie wielkości, emocje i wrażliwe uczucia trzeba zostawić za drzwiami. 91.Postępowanie wedle zasad. Należy postępować wedle przyjętego zestawu zasad. Te zasady mogą np. określać ilośc kodu który podlega przeglądowi (zwykle kilkaset linii), ile czasu należy poświęcić (kilka godzin), na co należy zwrócić uwagę itd. Ważne jest, aby uczestnicy znali swoje role i czego się od nich oczekuje. Dzięki temu przeglądy przebiegają sprawniej. 92.Przygotowanie. Oczekuje się, że każdy uczestnik będzie przygotowany do przeglądu. Zależnie od rodzaju przeglądu, uczestnicy mogą mieć różne role i muszą je znać, aby móc je w czasie przeglądu realizować. Większość problemów znalezionych w procesie przeglądu
1 Czytelniku, wybacz, ale oto znowu nomenklatura autora różni się od powszechnie przyjętej. Otóż zwykle inspekcje i przeglądy formalne to synomimy, określające przeglądy dokonywane szczegółowo, rygorystycznie, według opisanego procesu, natomiast cała reszta – to po prostu przeglądy, albo przeglądy nieformalne. Nie ma to większego znaczenia, ale dobrze orientować się w tym nomenklaturowym chaosie, żeby rozumieć o czym jest mowa.
Warto też pamiętać, że nie istnieje powszechnie przyjęta klasyfikacja różnych typów przeglądów i podane przez autora definicje przeglądu koleżeńskiego, ręcznego sprawdzianu i inspekcji różnią się w
Dziwne coś:znajduje się w czasie przygotowań, a nie podczas samego przeglądu2. 93.Pisanie raportu. Grupa dokonująca przeglądu musi stworzyć pisemny raport podsumowujący wyniki przeglądu. Raport musi być dostępny dla całego zespołu projektowego. Jest istotne aby wszyscy poznali wyniki przyglądu: ile znaleziono błędów, gdzie itp.
Najważniejsze dla formalnych przeglądów jest to, że odbywają się według ustalonego procesu. Przypadkowe „zebrać się razem i przelecieć się przez trochę kodu” nie wystarcza, a nawet może okazać się przeciwksuteczne. Jeśli proces odbywa się bałaganiarsko, wiele błędów pozostanie nieznalezionych, a uczestnicy będą mieli poczucie zmarnowango czasu.
Właściwie realizowane, przeglądy mogą być wyśmienitą metodą wczesnego znajdowania błędów. Wyobraźmy je sobie jako pierwsze siatki na motyle (rysuek 6.1), które chwytają największe „pluskwy” na samym początku procesu wytwarzania. Oczywiściem mniejsze „pluskwy” przedostaną się, ale zostaną schwytane w kolejnych fazach testowania, stosujących siatki o coraz mniejszych oczkach.
Rysunek 6.1 Formalne przeglądy są jak pierwsze w serii siatek do łapania błędów – „pluskiew”.
Oprócz znajdowania problemów i błędów, formalne przeglądy przynoszą szereg pośrednich korzyści.
szczegółach od definicji innych autorów, czy też od nazewnictwa stosowanego w przedsiębiorstwach (przyp. tłumacza).
2 Wywód byłby jaśniejszy, gdyby słowo przegląd stosować tylko do całego procesu, zaś zebranie na którym spisuje się znalezione błędy nazywać zebraniem przeglądowym, a nie – myląco – również przeglądem (przyp. tłumacza)..
94.Komunikacja. Przekazuje się sobie informacje, których nie ma w oficjalnych raportach. Na przykład, testerzy zajmujący się testowaniem metodami czarnej skrzynki mogą uzyskać cenny wgląd w obszary możliwych kłopotów. Początkujący programiści mogą nauczyć się nowych technik od doświadczonych programistów. Kierownictwo może uzyskać lepsze wyczucie, jak projekt posuwa się do przodu. 95.Jakość. Kod napisany przez programistę kontroluje się szczegółowo, linijka po linijce, funkcja za funkcją – co często powoduje, że programiści stają się staranniejsi. To nie znaczy że w przeciwnym razie byliby niechlujni – po prostu wiedząc, że kod będzie szczegółowo skontrolowany przez kolegów, odruchowo podejmuje się dodatkowy wyciłek żeby unikać błędów. 96.Powstanie ducha zespołu. Dobrze zorganizowane i poprowadzone, przeglądy mogą stać się forum, gdzie testerzy i programiści uczą się lepiej nawzajem rozumieć swoją pracę i potrzeby, i szanować nawzajem swoje umiejętności. 97.Rozwiązania. Może udać się znaleźć rozwiązania dla trudnych problemów, choć nie wszystkie typy przeglądów pozwalają na ich dyskutowanie w czasie zebrania przeglądowego. Może być lepiej, żeby taka dyskusja odbywała się poza zebraniem.
Te pośrednie korzyści zdarzają się, ale nie można na nie liczyć z pewnością. Zdarza się, że – z różnych powodów – członkowie zespołu pracują w izolacji od siebie. Formalne przeglądy to świetny sposób, żeby zebrać ich razem w jednym pokoju, dyskutujących wspólny problem.
Kontrole koleżeńskie
Najłatwiej zebrać razem członów zespołu i zlecić im wykonanie pierwszego wspólnego przeglądu w postaci przeglądu koleżeńskiego, który jest najprostszą formą przeglądu. Te metoda jest w istocie rozmową w stylu „pokaż mi jak to zrobiłeś, to ja ci pokażę jak ja to zrobiłem.”
Przeglądy koleżeńskie często odbywają się tylko z udziałem programisty – autora kodu oraz jednego czy dwóch testerów albo programistów w roli inspektorów. Ta niewielka grupa po prostu wspólnie przegląda kod i poszukuje problemów i opuszczeń. Aby mieć pewność że przegląd będzie wydajny (i nie zamieni się w przerwę na kawę), wszystkie cztery elementy formalnego przeglądu powinny być zastosowane: szukanie problemów, postępowanie według zasad, przygotowanie do przeglądu i napisanie raportu. Ponieważ przeglądy koleżeńskie są nieformalne, często omija się niektóre z tych elementów. Jednak samo zebranie się razem aby przedyskutowac kod niejednokrotnie wystarcza, żeby znaleźć błędy1.
Ręczny sprawdzian
Ręczne sprawdziany są krokiem wzwyż pod względem poziomu formalizmu w porównaniu z przeglądami koleżeńskimi. Ręczny sprwadzian polega na tym, że programista, który napisał kod, prezentuje kod programu „na piechotę” niewielkiej grupie programistów i testerów. Insepktorzy powinni zawczasu otrzymać kopie kodu, tak żeby mogli go skontrolować i zapisać komentarze i pytania, które chcą zadać w trakcie przeglądu. Ważne, by choć jeden z inspektorów był doświadczonym programistą.
Prezentator czyta kod linijka po linijce lub funkcja po funkcji i wyjaśnia, co i dlaczego kod wykonuje. Inspektorzy słuchają i pytają o wszystko, co budzi wątpliwości. Ponieważ w ręcznym sprawdzianie z reguły uczestniczy więcej osób niż w kontroli koleżeńskiej, jest bardzo ważne by wszyscy byli do zebrania przygotowani i by przestrzegać reguł. Ważne jest też, by po ukończonym sprawdzianie został napisany raport, streszczający jakie błędy zidentyfikowano i jak planuje się je skorygować.
Inspekcje
Inspekcje są najbardziej formalnym rodzajem przeglądów. Mają precyzyjną strukturę i wymagają, żeby wszyscy uczestnicy byli odpowiednio wyszkoleni. Inspekcje tym różnia się od przeglądów koleżeńskich i ręcznych sprawdzianów, że osoba która przedstawia kod, zwana prezentatorem, nie jest autorem kodu. Ta sytuacja wymaga, by ktoś inny oprócz autora rozumiał przedstawiany materiał w szczegółach.
Autor :1 Istnieje modna ostatnio metoda wytwarzania kodu, zwana “programowaniem ekstremalnym” (extreme programming, xP), polegająca na tym, że programiści pracują w parach: jeden pisze kod, drugi dokonuje na bieżąco “koleżeńskiej inspekcji” powstającego kodu; po jakimś czasie zamieniają się rolami (przyp. tłumacza).
Pozostali uczestnicy inspekcji nazywani są inspektorami1. Każdy otrzymuje odrębne zadanie zanalizowania kodu z innego punktu widzenia, np. użytkownika, testera, albo osoby zajmującej się konserwacją oprogramowania. To pozwala uwzglądnić w czasie inspekcji różne aspekty produktu i często pozwala zidentyfikować różne rodzaje błędów. Jeden z inspektorów otrzymuje nawet zadanie inspekcji kodu od tyłu – to znaczy od końca do początku – aby upewnić się czy materiał został zrealizowany jednolicie i w pełni.
Dwaj inspektorzy otrzymuja również rolę przewodniczącego i sekretarza, którzy odpowiadają za przestrzeganie reguł i płynny przebieg całego procesu.
Po zebraniu przeglądowym inspektorzy mogą zebrać się ponownie, aby przedyskutować znalezione problemy i wspólnie z przewodniczącym przygotować pisemny raport idnetyfikujący konieczne zmiany dla naprawienia błędów. Programista następnie przeprowadza te zmiany, a przewodniczący sprawdza, czy zostały zrobione właściwie. Zależnie od zakresu i wielkości zmian oraz od stopnia krytyczności oprogramowania, może zostać zarządzona kolejna inspekcja dla znalezienia pozostałych błędów.
Stwierdzono, że inspekcje są bardzo skuteczne w znajdowaniu błędów, zwłaszcza w dokumentacji projektu konstrukcji i w kodzie. Popularność inspekcji wzrasta, gdy coraz więcej przedsiębiortstw i zespołów projektowych odkrywa ich zalety. Standardy i reguły programowania
W trakcie formalnych przeglądów inspektorzy poszukują problemów i opuszczeń w kodzie programu. Istnieje wiele typowych błędów, przy których program po prostu nie będzie działać poprawnie. Najlepjej znajduje się je poprzez staranną analizę kodu – doświadczeni programiści i testerzy zwykle umieją to robić.
Istnieje też typ problemów, gdzie kod wprawdzie działałby poprawnie, ale nie jest napisany zgodnie ze standardem lub normą. Można to porównać ze zdaniem, które wprawdzie da się zrozumieć i przekazuje informację, ale nie spełnia zasad gramatyki i składni języka polskiego. Standardy to są ustalone, zapisane, wymagane zestawy reguł – co wolno, a czego nie wolno. Reguły to są sugerowane, praktyczne wskazówki, rekomendacje, zlecane sposoby. Stanardy nie dozwalają wyjątków. Reguły nie są równie obowiązujące.
Autor 1 W języku angielskim inspektorzy w procesie przeglądu nazywani są tu reviewers, a inspektorzy uczestniczący w inspekcji – inspectors. Po polsku podobne rozróżnienie byłoby językowo bardzo niezręczne, dlatego zachowano jednakową nazwę dla obu (przyp. tłumacza).
Może to brzmieć dziwnie, że fragment oprogramowania może działać, może być nawet przetestowany i bardzo stabilny, a mimo to niepoprawny, ponieważ nie spełnia innych kryteriów. Istnieją trzy główne powody, dla których przestrzega się standardów i reguł: 98.Niezawodność. Udowodniono, że kod napisany zgodnie ze standardem lub zestawem reguł jest bardziej niezawodny i ma mniej błędów niż kod nie przestrzegający standardów. 99.Czytelność/łatwość konserwacji. Kod spełniający standardy i reguły jest łatwiej przeczytać, zrozumieć i konserwować. 100.Przenośność. Kod musi być niekiedy przeniesiony na inny sprzęt albo skompilowany innym kompilatorem. Jeśli jest zgodny ze standardem, będzie przypuszczalnie łatwiej – może nawet zupełnie bezboleśnie – przenieść kod na inna platformę.
Wymagania projektu mogą niekiedy domagać się bezwzględnego przestrzegania zasad międzynarodowego albo krajowego standardu, albo tylko zalecać przestrzeganie wewnętrznch zasad zespołu projektowego. Co jest ważne, to stosować jakiś zestaw reguł i weryfikować jego przestrzeganie w trakcie formalnych przeglądów.
Przykłady standardów i reguł programowania
Rysunek 6.2 pokazuje przykład standardu programowania, który określa zasady stosowania instrukcji goto, while i if-else w języku C. Niewłaściwe używanie tych instrukcji często prowadzi do błędów w kodzie, i większośc standardów programowania podaje zasady posługiwania się nimi.
TEMAT: 3.05 Ograniczenia zastsowania struktur kontrolnych STANDARD Nie należy używać instrukcji go to (jak rónież etykiet). Pętla while powinna być stosowana zamiast pętli do-while, z wyjątkiem miejsc gdzie logika problemu jednoznacznie wymaga aby wnętrze pętli zostało wykonane chociaż raz niezależnie od wartości warunku kontrolnego pętli. Tam gdzie pojedyncze if-else może zastąpić continue, należy używać ifelse.
UZASADNIENIE Instrukcja go to jest zabroniona, ponieważ stwierdzono empirycznie korelację jej użycia z występowaniem błędów i trudnym do zrozumienia kodem, oraz z powodu abstrakcyjnego, że algorytmy powinny być wyrażone w postaci struktur ułatwiających skontrolowanie zgodności programu ze strukturą realizowanego procesu. Użycia do-while odradza się z tego powodu, że pętla powinna być kodowana tak, żeby mogła byc łatwo ominięta, to znaczy kontrola warunku pętli powinna być dokonywana przed wejściem do wnętrza pętli.
Rysunek 6.2 Przykład standardów kodowania wyjaśniający jak należy używać kilku struktur kontrolnych języka (Dostosowane z Zasady programowania w C++, Thomas Plum i Dan Saks, © 1991, Plum Hall).
Pokazany tutaj standard składa się z czterech głównych części: 101.Tytuł opisuje czego standard dotyczy. 102.Standard (albo reguła) opisuje treść standardu/reguły wyjaśniając szczegółowo co jest, a co nie jest dozwolone. 103.Uzasadnienie wyjaśnia motywację standardu tak aby programista mógł zrozumieć czemu nakazyana praktyka jest korzystna. 104.Przykład pokazuje proste fragmenty kodu stosującego się do standardu. Nie zawsze jest to konieczne.
Rysunek 6.3 jest opisem reguły stosowania funkcji języka C w języku C++. Zwróćmy uwagę na różnice w sformułowaniach. Tutaj zaczyna się od „należy starać się unikać”. Reguły nie są tak surowe jak standardy i pozwalają na pewną elastyczność w razie potrzeby.
TEMAT: 7.02 C_problemy – Problemowe dziedziny z C
REGUŁA Należy starać się unikać aspektów języka C niezgodnych w programowaniem w C++ 1. Nie używać setimp i longimp jeśli istnieją obiekty z destruktorami, które mogłyby powstać między wykonaniem setimp a wykonaniem longimp. 2. Nie stosować makro offsetof z wyjątkiem kiedy stosuje się do członków tej samej struktury prostej. 3. Nie mieszać I/O w stylu C (używającego stdio.h) z I/O w stylu C++ (używającego iostream.h lub stream.h) w tym samym pliku. 4. Unikać stosowania funkcji języka C takich jak memcpy albo memcap dla kopiowania albo porównywania obiektów innych typów niż wektor znaków lub prosta struktura. 5. Unikać makro NULL z języka C; używać w zamian 0.
UZASADNIENIE Każdy z tych aspektów dotyczy obszaru tradycyjnych zastosowań z języka C, które stwarzają pewne problemy w C++. Rysunek 6.3 Przykład reguł kodowania pokazuje jak stosować pewne aspekty C w C++ (Dostosowane z Zasady programowania w C++, Thomas Plum i Dan Saks, © 1991, Plum Hall).
To kwestia stylu
Istnieją standardy, istnieją reguły, a wreszcie jest też styl. Z punktu widzenia jakości i testu oprogramowania, styl jest bez znaczenia.
Każdy programista, tak samo jak każdy pisarz albo malarz, ma swój włany niepowtarzalny styl. Nawet kiedy przestrzegane są reguły, a użycie konstrukcji jest z nimi zgodne, zwykle nadal jest łatwo powiedzieć, kto jest autorem danego oprogramowania.
Czynnikiem wyróżniającym jest styl. W programowaniu może to być na przykład długość komentarzy albo nazewnictwo zmiennych, albo jakiej formy są wcięcia w kodzie pętli. To jest specyficzny wygląd kodu.
Niektóre zespoły, w zapale stwarzania standardów i reguł, zaczynają czasem krytykować styl kodu. Tester oprogramowania powinien trzymać się z dala od takich dyskusji. Kiedy wykonuje się przeglądy fragmentów oprogramowania, należy ograniczyć uwagi do tego co jest błędne, czego brakuje albo co nie jest zgodne z pisanymi standardami czy regułami. Należy sobie samemu zadać pytanie - czy ma się naprawdę do czynienia z błędem czy też z różnicą opinii, z kwestią stylu. W drugim wypadku nie może być mowy o błędzie.
Skąd wziąć standardy?
Jeśli projekt musi stosować się do istniejących standardów, albo jeśli tylko chce się porównać kod ze standardami, do dyspozycji ma się kilka źródeł.
Narodowe i międzynarodowe standardy w dziedzinie języków programowania i technologii informatycznych można znaleźć: 105.American National Standard Institute (ANSI), www.ansi.org 106.International Engineering Consortium (IEC), www.iec.org 107.International Organisation for Standardisation (ISO), www.iso.ch 108.National Committee for Information Technology Standards (NCITS), www.ncits.org
Można też znaleźć dokumentację reguł programowania i opisy najlepszych praktyk w następujących organizacjach: 109.Association for Computing Machinery (ACM), www.acm.org 110.Institute of Electrical and Electronics Engineers, Inc (IEEE), www.ieee.org
Często można też uzyskać informację od producenta oprogramowania. Wielu producentów publikuje standardy do własnego oprogramowania i można je kupować za niewielką opłatą. Lista kontrolna do przeglądów kodu
Pozostała część tego rozdziału zajmuje się problemami, których należy szukać dokonując formalnego przeglądu kodu. Te listy kontrolne1 stosuje się oprócz porównywania kodu ze standardami oraz oprócz kontroli czy kod spełnia wymagania konstrukcyjne.
Aby rzeczywiście rozumieć i stosować opisane poniżej punkty kontrolne, należy mieć pewne doświadczenie z programowaniem. Jeśli nie ma się dosyć doświadczenia, warto przeczytać książkę dla początkujących, na przykład „Jak nauczyć się samemu programowania w 24 godziny” z wydawnictwa Sams Publishing2 zanim podejmie się próby szczegółowej analizy kodu programu.
Autor:1 Obawiam się, że taka wiedza może okazać się dramatycznie niewystarczająca (przyp. tłumacza).
Błędy w referencjach zmiennych
Błędy w referowaniu zmiennych często spowodowane są użyciem zmiennej, stałej, wektoru, ciągu znaków albo rekordu które nie zostały zainicjalizowane w sposób pasujący do trybu czy sposobu użycia i referowania. 111.Czy istnieje referencja do niezainicjalizowanej zmiennej? Szukanie opuszczeń jest tu równie ważne jak szukanie błędów. 112.Czy indeks wskazyjący pozycję w wektorze znaków albo w ciągu znaków zawsze jest w zakresie zgodnym z rozmiarami wektora? 113.Czy istnieją jakieś możliwe błędy „o jeden” w indeksowych referencjach do wektorów? Przypomnijmy sobie listing 5.1 z rozdziału 5ego. 114.Czy używa się zmiennych tam gdzie stała byłaby odpowiedniejsza, na przykład do kontroli granic wektora? 115.Czy zmiennej jest kiedykolwiek przydzielona wartość innego typu niż zmienna? Na przykład, czy kod przydziela wartość zmiennoprzecinkową zmiennej całkowitoliczbowej? 116.Czy pamięć, do której referują wskażniki, została przydzielona? 117.Kiedy wspólna struktura danych jest używana w kilku funkcjach, czy definicja struktury jest wszędzie taka sama?
Błędy w deklarowaniu zmiennych
Błędy w deklaracjach są spowodowane przez niewłaściwe deklarowanie zmiennych lub stałych. 118.Czy wszystkie zmienne mają zadeklarowaną właściwą długość, typ i rodzaj pamięci? Na przykład, czy zmienna nie powinna być raczej zadeklaraowana jako ciąg znaków niż jako wektor znaków? 119.Czy zmienne inicjalizowane w momencie deklaracji są inicjalizowane poprawnie i wartościa zgodną ze swoim typem? 120.Czy istnieją zmienne z podobnymi nazwami? Nie jest to koniecznie błędem, ale być może symptomem, że pomieszały się zmienne o podobnych nazwach z różnych miejsc w programie.
Wersja 9 października 2001, Bogdan Bereza
Ron Patton „Test oprogramowania” Część II strona 59 (86) 121.Czy istnieją zadeklarowane zmienne, których się potem nie używa albo użyte są tylko jeden raz? 122.Czy wszystkie zmienne zadeklarowane są w swoich modułach? Jeśli nie, czy jest zrozumiałe że zmienna jest wspólna z najbliższym modułem wyższego rzędu?
Błędy obliczeniowe
Błędy obliczeniowe to po prostu błędna matematyka. Wynik obliczenia jest fałszywy. 123.Czy gdzieś w obliczeniach używa się zmiennych różnych typów, jak np. dodawanie liczby całkowitej do zmiennoprzecinkowej? 124.Czy gdzieś w obliczeniach używa się zmiennych tego samego typu ale różnej długości – na przykład dodanie bajtu do słowa? 125.Czy zasady konwersji kompilatora wobec zmiennych różnych typów lub długości są wzięte pod uwagę w kodzie realizującym obliczenia? 126.Czy zmienna której przydzielony zostanie wynik obliczenia jest mniejsza niż wynik wyrażenia po prawej stronie? 127.Czy możliwy jest niedomiar lub przepełnienie w trakcie obliczeń? 128.Czy może gdzieś wystąpić dzielenie przez zero? 129.Czy w wypadku działań całkowitoliczbowych kod uwzględnia możliwość utraty dokładności, np. przy dzieleniu? 130.Czy wartość zmiennej może przekroczyć wartość „rozsądną”? Na przykład, czy wynik obliczania prawdopodobieństwa może być mniejszy niż zero lub wiekszy niż 100%? 131.W wyrażeniach zawierających wiele operatorów, czy zasady kolejności obliczania oraz zasady priorytetu operatorów są uwzględnione? Czy potrzebne są nawiasy dla wyjaśnienia?
Błędy w porównaniach
Mniejsze niż, większe niż, równe, nierówne, fałsz, prawda. Porównania i decyzje są zwykle bardzo narażone na błędy warunków brzegowych.
132.Czy porównanie jest poprawne? To się wydaje trywialne, ale prawie zawsze jest jakas wątpliwość czy porównanie ma być np. „mniejszy niż” czy też „mniejszy niż lub równy”. 133.Czy dokonuje się porównań między wartościami zmiennoprzecinkowymi? Jeśli tak, czy mogą wystąpić jakieś kłopoty z dokładnością? Czy na przykład 1.00000001 jest dostatecznie blisko 1.00000002, żeby porównanie wykazało równość? 134.Czy wyrażenie boole‘owskie wyraża właściwie to co powinno? Czy obliczenia na zmiennych boole‘owskich są poprawnie zbudowane? Czy kolejność oszacowania jest wzięta pod uwagę? 135.Czy argumenty wyrażenia boole‘owskiego są boole‘owskie? Czy na przykład zmienna całkowitoliczbowa zawierająca liczbę całkowitą nie jest używana w boole‘owskich obliczeniach?
Błędy przepływu sterowania
Błędy przepływu sterowania są skutkiem nieprzewidzianego – innego niż zamierzone – działania pętli i innych konstrukcji języka. Spowodowane są zwykle – bezpośrednio lub pośrednio – przez błędy w obliczeniach albo w porównaniach. 136.Jeśli język zawiera takie konstrukcje jak begin…end oraz do…while, czy zakończnia są jawne i czy właściwie zamykają konstrukcje? 137.Czy program, moduł, subrutyna albo pętla kiedykolwiek zakończą działania? Jeśli nie, czy to jest w porządku? 138.Czy istniej ryzyko przedwczesnego wyjścia z pętli? 139.Czy istnieje możliwość, że kod we wnętrzu pętli nie zostanie wykonany ani razu i czy jest to do przyjęcia? 140.Jeśli program zawiera wielokrotne rozgałęzienie, takie jak instrukcja switch… case, czy wartość zmiennej indeksowej może przekroczyć wartości indeksów możliwych rozgałęzień? Jeśli tak, czy istnieje odpowiednia porcedura postępowania w tym wypadku? 141.Czy istnieją błędy „o jeden”, które mogą spowodować niezaplanowane wykonanie wnętrza pętli?
Błędy w parametrach procedur
Błędy w parametrach procedur biorą się z niewłaściwego przekazywania danych do podprocedur. 142.Czy typ i wielkość parametrów otrzymanych przez procedurę zgodne są z wysłanymi przez kod przywołujący porcedurę? Czy ich kolejność jest poprawna? 143.Czy jeśli procedura ma wiele punktów wejścia (brr…), to istnieją odniesienia do parametrów nie zdefiniowanych dla danego punktu wejścia? 144.Czy jeśli zmienne posyła się do procedury jako parametry, czy ich wartość może zostać przypadkowo zmieniona przez procedurę? 145.Czy procedura zmienia wartość parametru, który ma być tylko wartością wejściową? 146.Czy skala dla poszczególnych parametrów jest taka sama w rutynie wywołującej i wywołanej – np. europejskie i amerykańskie miary? 147.Jeśli występują zmienne globalne, czy mają one takie same definicje we wszystkich procedurach, które z nich korzystają?
Błędy danych wejściowych i wyjściowych
Ta klasa błędów odnosi się do wszelkich działań związanych z czytaniem z pliku, przyjmowaniem danych z klawiatury albo z myszy, pisanie na urządzeniu wyjścia, np. na drukarce albo na ekranie. Podane poniżej punkty są bardzo ogólnikowe i uproszczone. Należy je uzupełnić, żeby zastosować do różnych typów oprogramowania i urządzeń, które się testuje. 148.Czy oprogramowanie dokładnie spełnia wymagania formatu danych pisanych albo czytanych przez urządzenie zewnętrzne? 149.Jeśli plik albo urządzenie peryferyjne nie jest gotowe, czy program radzi sobie właściwie z tą sytuacją? 150.Czy oprogramowanie radzi sobie gdy zewnętrzne urządzenie jest odłączone, nie odpowiada, albo jest przepełnione w trakcie czytania lub pisania? 151.Czy wszelkie możliwe błędy są obsługiwane przez oprogramowanie w przewidywalny sposób?
152.Czy wszystkie komunikaty błędów zostały sprawdzone i są trafne, mają odpowiednią treść, są poprawne gramatycznie i ortograficznie?
Inne kontrole
Poniższa lista zawiera pozycje, które nie pasowały do pozostałych kategorii. Nie jest ona w żadnym razie kompletna, ale powinna być dobrym początkiem dla sporządzenia listy pełniejszej, stosownej dla konkretnego projektu. 153.Czy oprogramowanie będzie działać poprawnie z wszystkimi wymaganymi językami? Czy jest w stanie posługiwać się rozszerzonym kodem ASCII? Czy używa Unicode zamiast ASCII? 154.Jeśli oprogramowanie ma być przenośne na inne kompilatory i mikroprocesory, czy zostalo to wzięte pod uwagę? Przenośność, jeśli wymagana, staje się często dużym problemem jeśli się jej nie planowało i nie testowało pod jej kątem. 155.Czy uwzględnione zostały wymagania kompatybilności tak żeby oprogramowanie działało poprawnie z różną ilością dostępnej pamięci, różnymi rodzajami sprzętu takiego jak karty dźwiękowe i graficzne, i z różnymi urządzeniami peryferyjnymi, jak drukarki i modemy? 156.Czy kompilacja programów powoduje różne komunikaty „ostrzegawcze” albo „informacyjne”? Zwykle oznacza to że w kodzie kryje się coś wzbudzającego wątpliwości. Puryści twierdziliby, że żadne komunikaty ostrzegawcze nie są dopuszczalne. Podsumowanie
Badanie kodu – statyczne testowanie metodami szklanej skrzynki – okazało się wielokrotnie skutecznym sposobem wczesnego znajdowania błędów. Ta metoda wymaga sporo przygotowań, aby mogła być produktywna, ale wiele badań pokazuje, że spędzony tym czas dobrze się opłaca. Żeby zaś uczynić ten rachunek jeszcze atrakcyjniejszym, dostępne są dzis programy pozwalające zautomatyzować dużą część pracy. Istnieją programy sprawdzające zgodność kodu źródłowego z wieloma istniejącymi standardami i z własnymi regułami, które można dostosowywać do potrzeb klienta. Również kompilatory są dzisiaj na tyle udoskonalone, że uruchomiwszy pełny arsenał ich możliwośi kontrolnych, można automatycznie zidentyfikowac większość problemów znajdujących się na omówionej na poprzednich stronach liście. Te narzędzia nie likwidują potrzeby przeglądów i inspekcji kodu, tylko ułatwiają je znacznie i dają testerom czas, aby móc szukać błędów jeszcze głębiej.
Jeśli w zespole projektowym nie testuje się obecnie na tym poziomie, a testerzy mają nieco doświadczenia w programowaniu, można zaproponować rozważenie takiej możliwości. Programiści i kierownictwo mogą się początkowo obawiać tego przedsięwzięcia, nie bardzo wierząc, by zyski rzeczywiście były aż tak duże – w końcu trudno jest udowodnić, że na przykład znalezienie błędu podczas inspekcji zaoszczędziło projektowi pięć dni, które trzeba by było spędzic wiele miesięcy później podczas testowania metodami czarnej skrzynki. Niemniej, statyczne testowanie metodami szklanej skrzynki nabiera coraz więcej impetu, i w niektórych branżach nikt nie odważy się dziś dostarczać niezawodnego oprogramowania, nie poddawszy go statycznemu testowaniu. Pytania
Pytania mają na celu ułatwienie zrozumienia. W aneksie A „Odpowiedzi do pytań” znajdują się prawidłowe rozwiązania – ale nie należy ściągać! 1.Wymień kilka korzyści wynikających ze stosowania statycznego testowania metodami szklanej skrzynki. 2.Prawda czy fałsz: statyczne testowanie metodami szklanej skrzynki pozwala znaleźć zarówno brakujące elementy jak i problemy. 3.Jakie są kluczowe elementy formalnych przeglądów? 4.Oprócz poziomu formalizmu, jaka jest zasadnicza różnica między inspekcjami a innymi rodzajami przeglądów? 5.Jeśli programista został poinformowany, że wolno mu używać nazw zmiennych nie dłuższych niż osiem znaków i wszystkie muszą zaczynać się dużą literą, czy mamy do czynienia ze standardem czy z regułą? 6.Czy listę kontrolną do przeglądów kodu opisaną w tym rozdziale powinno się przyjąć jako standard waszego zespołu do weryfikacji kodu?