Inzynieria programowania, IP-P.Szmal, INFORMATYKA z. 22Nr kol


rozdział 1

Testowanie programów

  1. Testowanie programów

    1. Cel ćwiczenia

Celem ćwiczenia jest zapoznanie się z wybranymi metodami testo­wania oprogra­mo­wania i typowymi środkami pomocnymi w testowa­niu oraz wykorzystanie ich w praktyce, w wybranym systemie progra­mowania.

    1. Podstawy teoretyczne

Każdy program powinien być przede wszystkim niezawodny. Pojęcie nieza­wodności można rozumieć, w pewnym uproszczeniu, jako brak po­datności na awarie oprogramowania. Przyjmijmy jako defini­cję awarii określenie sfor­muł­owane przez J. Goode­nougha:

Awaria to każdy efekt lub zacho­wanie, którego wystąpienie jest niedo­pu­szczal­ne w normalnych warunkach działania, gdzie to, co „niedo­pu­szczalne” i „nor­malne”, musi być określone dla każdego syste­mu.

Wówczas przykładami awarii mogą być błędne wyniki lub brak wyników, zmniejszenie efektywności programu (zaskakująco długie przetwarzanie dla pewnych danych) lub niszczenie danych użytkownika. Działania takie mogą być spowodowane błędami w strukturze programu lub niepoprawnym wypeł­nianiem specyfikacji.

Niezawodność łączy się ściśle z poprawnością programu. Najogólniej można po­wie­dzieć, że program jest poprawny, jeżeli zawsze działa zgodnie z sensownymi oczekiwaniami użytkownika i intencją programisty. Definicja taka jest bardzo ogólna i elastyczna, bo bazuje na pojęciach wysoce subiektywnych. Program prawidłowo zaprojektowany i napisany powinien być zgodny ze swoją specyfikacją. Należy więc upewnić się, czy badany program istotnie tę specyfikację spełnia. Z drugiej strony, czasami sama specyfikacja może nie obejmować pewnych sytuacji lub być niedoskonała albo niespójna w inny sposób, i wówczas w pełni z nią zgodny program także może ulec awarii. Należy więc sprawdzić i specyfikację.

    1. Definicja testowania

Testowanie jest to zbiór czynności wykonywanych z intencją wykry­cia w programie jak największej liczby błędów. Jednym z jego głównych składników jest obserwacja zgodności produkowanych przez program wyników z wcześniej przygotowanymi poprawnymi wyni­ka­mi odniesienia. Proces ten może prowa­dzić do uznania, że dany program działa poprawnie we wszystkich przypadkach, w których ma działać, lub do wykrycia błędu.

Celem testowania programu jest upewnienie się, że program rozwią­zuje to zadanie, do którego został zaprojektowany, i że w każdych warunkach daje poprawne wyniki. Jest to proces różny od procesu uruchamiania programu. Program uruchomiony nie zawiera błędów sygnalizowanych przez translator i jawnie niepoprawnych fragmentów kodu oraz daje jakieś wyniki. Czy wyniki te są poprawne, zgodne z oczekiwaniami ustalonymi w specyfikacji, pozwala ocenić tes­towanie.

Nie jest możliwe dokładne określenie, jak powinno przebiegać testowa­nie konkretnego programu. Można jednak sformułować kilka wskazó­wek dotyczących organizacji procesu testowania, które mogą pomóc w prawi­dłowym przetes­towa­niu programu.

Należy dążyć do:

Określając granice procesu testowania trzeba wspomnieć o licz­bie wykonywanych testów. Chcąc starannie przetestować cały program, należałoby wykonać testowanie gruntowne. Polega ono na wykonaniu programu dla wszystkich możliwych kombinacji danych wejściowych. Jest to prawie zawsze niemożliwe ze względu na niezbędny w tym celu czas i wysiłek, choć byłby to jedyny sposób udowodnienia całkowitej poprawności programu. W praktyce, ze względu na efektywność testowa­nia, należy stosować możliwie małą, lecz dostateczną liczbę zestawów danych tes­towych, przy czym powinny być one dobie­rane z odrobiną wyobraźni i podej­rzli­wości w stosunku do działania programu. Mimo istnienia wielu formalnych metod, w praktyce programista powinien bazować w znacznym stopniu na swoim sprycie i intuicji.

Testując dany program nal­eży przeprowadzić dwa rodzaje testów. Po pier­wsze, trzeba przekonać się, czy program rea­lizuje właśnie to zada­nie, które zosta­ło sformułowane. Po wtóre, nale­ży uzyskać pewność, że działa poprawnie.

Możliwe są dwa skrajnie odmienne podejścia do testowania progra­mu: względem struktury wewnętrznej (kodu) i względem specyfikacji zewnętrznej.

Można jako podstawę w cza­sie testowania potraktować kod programu. Wtedy zabezpie­czymy się przed błędami wykonania (ang. run-time errors) i wszystkie instrukcje będą się wykonywały poprawnie, jednak nie wykryjemy faktu, że program jest niezgodny ze spe­cy­fi­kacją, tzn. robi nie to, co należało.

Jeśli zaś nie będziemy inte­resować się kodem, możemy testowaniem objąć jedynie spe­cyfika­cję. Wówczas mamy sytuację odwrotną - jeżeli umiejętnie dobierzemy dane testowe, możemy wy­kryć wiele błędów logicznych, jednak nie możemy gwarantować, że program nie zakończy się błę­dem wykonania. Wynika stąd, że dla właści­wego przetestowania programu konieczna jest znajo­mość i sprawdzenie zarówno specyfikacji, jak i kodu programu.

      1. Testowanie struktury wewnętrznej

Przy testowaniu struktury wewnętrznej pojedynczego modułu (testowaniu względem kodu) konieczna jest znajomość tekstu źródłowego programu. Generalnie przyjmuje się, że warun­kami koniecznymi zakończenia testowania względem kodu są:

  1. Doprowadzenie do wykonania każdej instrukcji co najmniej raz, lub - równoważnie - do przejścia każdej z gałęzi przepływu sterowania w module. Chodzi o to, aby każdy wa­runek (punkt w programie, gdzie sterowanie rozgałęzia się, czyli zaczyna się nowa ga­łąź) podczas wykonywania testów przyjął wartość zarówno prawda, jak i fałsz. Trudno powiedzieć, ile razy należy powtórzyć wykonanie programu, aby powyższe warunki spełnić - zależy to od za­dania, które program wykonuje.

  2. Wykonanie wnętrza każdej pętli minimalną liczbę razy, małą liczbę razy oraz bardzo dużą (lub maksymalną, o ile można taką określić) liczbę razy. Osiąga się to przez dobór od­powiednich danych testowych.

Przygotowując dane testowe dla testowania względem kodu korzystamy z diagramów prze­pływu sterowania (DPS) i tworzonych na ich podstawie macierzy pokrycia gałęzi. Tech­nika posłu­giwania się nimi została przedstawiona w Dodatku A. Szerzej o zasadach doboru danych testowych traktuje punkt 1.6.

      1. Testowanie specyfikacji zewnętrznej

W przypadku testowania specyfikacji zewnętrznej program traktujemy jako „czarną skrzynkę”. Znamy jedynie liczbę i rodzaj danych podawanych na wejściu, liczbę i rodzaj da­nych wyjściowych oraz zdefiniowaną w specyfikacji zależność pomiędzy danymi wejścio­wymi a wyjściowymi.

W tym przypadku dobór danych testowych, a szczególnie moment, w którym uznamy te­stowa­nie za zadowalające i wiarygodne, w jeszcze większym stopniu zależy od doświadcze­nia i intuicji testującego. Wskazówki na temat doboru danych testowych znajdują się w punkcie 1.6.

W czasie przygotowywania zestawów danych testowych należy brać pod uwagę: