background image

Testowanie oprogramowania 

Źródło: Krzysztof Sacha „Inżynieria programowania” PWN W-wa 2010 

 
Testowanie  jest  procesem  eksperymentalnego  badania  programu  lub  jego 
komponentu,  polegającym  na  próbnym  wykonywaniu  w  znanych  warunkach, 
rejestrowaniu wyników i ocenianiu na ich podstawie właściwości tego programu lub 
komponentu.  
 

1. Poziomy testowania 

Testowanie jednostkowe 
Testowanie integracyjne 
Testowanie systemowe 

testy funkcjonalne (functional testing),  
testy wydajnościowe (performance testing),  
testy przeciążeniowe (stress testing),  
testy bezpieczeństwa (security testing),  
testy odporności (recovery testing),  
testy zgodności (compatibility testing),  
testy dokumentacji (documentation testing),  

Testowanie akceptacyjne 

 

2. Organizacja procesu testowania 

2.1. Planowanie testów 
2.2. Przygotowanie testów 
2.3. Testowanie a usuwanie defektów 

Po wykonaniu serii testów i wprowadzeniu poprawek powstaje kolejna 
wersja programu, która jest poddawana podwójnemu sprawdzeniu: 

 

czy  wszystkie  dotychczas  działające  funkcje  programu  działają 
nadal (testy regresji), 

 

czy  wszystkie  wykryte  błędy  zostały  rzeczywiście  usunięte 
(retesty). 

 

background image

 

3. Metryki Testowania 

Aby  móc  efektywnie  planować  i  zarządzać  wykonaniem  procesu  testowania 
oprogramowania,  potrzebny  jest  jakiś  sposób  pomiaru  jakości  testów  oraz  sposób 
pomiaru postępu prac w czasie trwania procesu testowania. Narzędziem pomiaru są 
metryki  testowania,  czyli  ilościowe  miary  odzwierciedlające  różne  cechy 
zaprojektowanych, lub już wykonanych, testów.  
analiza pokrycia kodu (code coverage analysis).  
metryki pokrycia kodu (code coverage metrics),  
analizy stopnia pokrycia wymagań testami funkcjonalnymi.  
 
3.1. Metryki pokrycia kodu 

Pokrycie bloków instrukcji 
Pokrycie decyzji (decision coverage) 
Pokrycie ścieżek 

 
3.2. Metryki pokrycia wymagań 

Pokrycie wymagań (requirements coverage) 
Pokrycie błędów 
Testowanie przypadków użycia: 

 

pokrycia biznesowych przypadków użycia zestawami testów, 

 

pokrycia  systemowych  przypadków  użycia  scenariuszami  przypadków 
testowych, 

 

pokrycia scenariuszy systemowych przypadków użycia przez przypadki 
testowe. 

 
3.3. Inne metryki 

Liczba wykrytych defektów 
Częstość defektów 
Procent defektów poprawionych 
Szacowanie liczby wszystkich defektów 
 

 

background image

 
 

4. Metody testowania 

Celem  testowania  jest  doświadczalne  porównanie  wyników  działania  programu  ze 
wzorcem, którym jest specyfikacja tego programu. Jeśli wyniki są zgodne, to program 
uznaje się za poprawny.  
 
4.1 Testowanie czarnej skrzynki 

Analiza klas równoważności 
Analiza wartości brzegowych (boundary value analysis) 
Testowanie sposobów użycia (use case testing) 
Testowanie losowe (Monte Carlo method) 

4.2. Testowanie białej skrzynki 

Testowanie  ścieżek  (path  testing)  -  Można  w  tym  celu  wykorzystać  pułapki 
programu uruchomieniowego (debugger). 
Testowanie mutacyjne (mutation testing) 

 

5. Automatyzacja testowania 

Narzędzia elementarne - sterowniki i namiastki 
Automatyzacja testów jednostkowych biblioteki Junit Nunit 
Narzędzia pokrycia kodu (code coverage tools), 
Odtwarzanie działań użytkownika (record and playback feature) 
Testowanie wydajności 

 

 

 

background image

Testowanie  jest  procesem  eksperymentalnego  badania  programu  lub  jego 

komponentu,  polegającym  na  próbnym  wykonywaniu  w  znanych  warunkach, 
rejestrowaniu wyników i ocenianiu na ich podstawie właściwości tego programu lub 
komponentu.  Przedmiotem  oceny  może  być  poprawność  wytwarzanych  przez 
program wyników, wydajność lub szybkość obliczeń albo inne właściwości określone 
w specyfikacji wymagań. 

Aby uzyskać gwarancję prawidłowego zachowania w każdej sytuacji, należałoby 

sprawdzić  działanie  programu  dla  wszystkich  możliwych  wartości  danych 
wejściowych.  Astronomiczna  liczba  możliwych  wartości  danych,  które  w  dodatku 
mogą  być  wprowadzane  w  różnej  kolejności  i  w  różnym  czasie,  sprawia,  że  takie 
pełne  sprawdzenie  programu  jest  niemożliwe  do  wykonania.  Dlatego  w  praktyce 
zastępuje  się  pełne  sprawdzenie  programu  pewną  liczbą  eksperymentów 
polegających  na  wprowadzeniu  wybranych  wartości  danych  wejściowych  i 
porównaniu  otrzymanych  wyników  z  oczekiwaniami.  Każdy  eksperyment,  który 
można  opisać  w  kategoriach  wartości  wprowadzanych  danych,  akcji  wykonywanej 
przez  użytkownika  i  oczekiwanych  wyników,  jest  nazywany  przypadkiem  testowym 
(test case). 

Liczba  przypadków  testowych  oraz  sposób  doboru  wartości  danych  mają 

decydujący  wpływ  na  jakość  i  wiarygodność  procesu  testowania.  Dlatego  ważną 
czynnością poprzedzającą etap testowania jest projektowanie testów, mające na celu 
określenie  takiego  zestawu  przypadków  testowych,  który  umożliwi  efektywne 
sprawdzenie wszystkich aspektów poprawności programu w ograniczonym czasie. 

Wykonanie  pewnego  zestawu  testów  nie  jest  czynnością  jednorazową.  Każda 

zmiana  już  przetestowanego  fragmentu  programu,  związana  z  poprawianiem 
ujawnionych błędów lub z ulepszaniem jego funkcji, może wprowadzić nowe błędy lub 
doprowadzić do ujawnienia się błędów istniejących od dawna, lecz niewidocznych w 
poprzedniej wersji programu. Dlatego dobrą praktyką jest powtarzanie wszystkich już 
wykonanych  testów  po  każdej  zmianie  poddanego  testom  programu.  Takie 
powtarzane testy, których celem jest upewnienie się, że pomimo dokonanych zmian 
program  nadal  działa,  są  nazywane  testami  regresji.  Zaniechanie  testów  regresji 
może doprowadzić do pozostawienia błędów w działaniu programu. 

Testowanie  oprogramowania  jest  złożonym  procesem,  pochłaniającym  wiele 

czasu  i  zasobów  oraz  wymagającym  starannego  przygotowania.  Dlatego  różne 

background image

działania związane z testowaniem występują w różnych fazach procesu wytwórczego. 
Podstawowe  działania  obejmują  przygotowanie  planu  testów,  zaprojektowanie 
przypadków  testowych,  przygotowanie  środowiska  testowego,  testowanie,  ocenę 
wyników i usunięcie błędów w działaniu programu. 

 
 
 

1. Poziomy testowania 

Podstawowym celem testowania jest znalezienie i usunięcie błędów w działaniu 

programu.  Każdy  błąd  (error),  czyli  objaw  błędnego  działania  programu  ujawniony 
podczas  testów,  świadczy  o  jakimś  defekcie  (fault)  znajdującym  się  w  kodzie 
testowanego  programu.  Znalezienie  tego  defektu  na  podstawie  zaobserwowanych 
objawów  błędu  jest  tym  trudniejsze,  im  dłuższa  droga  dzieli  miejsce  defektu  od 
miejsca ujawnienia się błędu. Aby skrócić tę drogę i ułatwić lokalizowanie defektów, 
można  rozpocząć  testowanie  jeszcze  przed  integracją  całości  oprogramowania  i 
testować najpierw poszczególne jednostki programu, potem ich współdziałanie, a na 
końcu - działanie całego systemu. Przyjęcie takiej organizacji tworzy kilka poziomów 
testowania,  przeznaczonych  na  ocenę  różnych  właściwości  i  różnych  aspektów 
działania oprogramowania. 

 

 

Rysunek 1. Model V procesu testowania oprogramowania 

Model  procesu  testowania,  pokazany  na  rys.  1,  przedstawia  kolejność  (linie 

ciągłe)  oraz  związki  (linie  przerywane)  poziomów  testowania  z  etapami  lub 
działaniami  procesu  rozwoju  oprogramowania.  Dobrą  praktyką  inżynierską  jest 
projektowanie zestawu testów w tej fazie rozwoju, w której są rozważane te aspekty 

background image

oprogramowania,  które  będą  podlegać  testowaniu.  Praktyka  dowodzi,  że 
opracowanie  koncepcji  testowania  sprzyja  lepszemu  zrozumieniu  i  większej 
jednoznaczności sformułowania wymagań. 

 
Testowanie jednostkowe 
Przedmiotem  testowania  jednostkowego  (unit  testing,  module  testing)  są 

podstawowe  jednostki  programu  opisane  w  projekcie  szczegółowym.  Postać  tych 
jednostek  zależy  od  technologii  implementacji  -  mogą  być  nimi  podprogramy 
(procedury, funkcje) napisane w języku strukturalnym, skrypty SQL albo metody lub 
klasy  zapisane  w  języku  obiektowym.  Celem  testowania  na  tym  poziomie  jest 
sprawdzenie  zgodności  działania  wszystkich  opracowanych  jednostek  z  ich 
specyfikacją, wynikającą z projektu, oraz wykrycie i usunięcie jak największej liczby 
błędów. 

Szczegółowy  projekt  programu  powstaje  w  procesie  kaskadowym  w  końcowej 

części fazy projektowania. Natomiast w procesie iteracyjnym projekt taki powstaje w 
każdej  iteracji  fazy  konstrukcji  i  dotyczy  tej  części  oprogramowania,  która  jest 
budowana w bieżącej iteracji. W tym też czasie powinny zostać zaplanowane testy 
jednostkowe.  Sposób  realizacji  testowania  jednostek  zależy  od  wymaganej 
niezawodności programu. W tych zastosowaniach, w których wymagania są wysokie, 
testowanie  jednostkowe  tworzy  odrębny  etap  procesu  wytwórczego,  wykonywany 
przez  niezależny  zespół  testujący.  W  pozostałych  przypadkach  testowanie 
jednostkowe realizują na ogół deweloperzy, którzy opracowali testowane programy, a 
czynności testowania nakładają się na okres implementacji programów. 

Problemem  tego  poziomu  testowania  jest  zależność  testowanej  jednostki  od 

innych jednostek programu, które np. wywołują testowany podprogram albo są przez 
niego  wywoływane.  Przeprowadzenie  testów  wymaga  w  takim  przypadku  użycia 
specjalnego  oprogramowania  wspomagającego  albo  opracowania  sterowników 
testowych,  wywołujących  badaną  jednostkę  z  odpowiednimi  argumentami,  oraz 
namiastek,  symulujących  działanie  brakujących  jednostek  wywoływanych. 
Przygotowane  w  ten  sposób  środowisko  testowania  powinno  być  zachowane  i 
wykorzystane do testów regresji - po poprawkach związanych z usuwaniem błędów 
oraz później, po zmianach wprowadzanych w kolejnych wersjach programu. 

 

background image

Testowanie integracyjne 
Połączenie dwóch współdziałających jednostek tworzy nową jednostkę, w której 

ujawniają  się  błędy  związane  z  niedopasowaniem  mechanizmów  ich  współpracy. 
Przedmiotem działań podejmowanych podczas testowania integracyjnego (interface 
testing) jest łączenie jednostek programu w coraz większe komponenty i sprawdzanie 
zgodności  ich  działania  ze  specyfikacją  wynikającą  z  projektu  architektury 
oprogramowania.  Celem  testów  jest  sprawdzenie  funkcjonowania  interfejsów  - 
sposobu  wywoływania  usług  i  przekazywania  argumentów,  postaci  zwracanych 
rezultatów, zgodności jednostek miary używanych we współpracujących jednostkach, 
zgodności  wyjątków  zgłaszanych  w  jednej,  a  obsługiwanych  w  innej  jednostce  itp. 
Wszystkie  wykryte  błędy  są  usuwane,  a  cały  proces  trwa  aż  do  zintegrowania  i 
przetestowania działania całości oprogramowania. 

Projekt  architektury  oprogramowania  powstaje  w  procesie  kaskadowym  w 

początkowej części fazy projektowania. W procesie iteracyjnym projekt taki powstaje 
w  fazie  opracowania  i  podlega  uszczegółowieniu  podczas  konstrukcji 
oprogramowania.  Wraz  z  opracowywaniem  architektury  powinien  też  powstać  plan 
testowania  integracyjnego.  Wykonanie  czynności  integracji  i  testowania  programu 
tworzy  na  ogół  osobny  etap  działań,  wykonywany  po  zakończeniu  implementacji: 
całości  -  w procesie  kaskadowym,  lub  części  -  w  procesie  iteracyjnym.  Testowanie 
mogą przeprowadzać deweloperzy lub wyspecjalizowany zespół testujący. 

Proces  integracji  programu  może  przebiegać  w  różny  sposób.  W  metodzie 

„wielkiego  wybuchu"  zakłada  się  złożenie  wszystkich  jednostek  oprogramowania  i 
testowania od razu całości. Mankamentem tego podejścia jest trudność lokalizowania 
ujawnianych  błędów.  Doświadczenie  pokazuje,  że  nakładające  się  na  siebie 
wielokrotne błędy potrafią maskować swoje istnienie, sumować się w dziwny sposób 
lub  wykazywać  objawy  sugerujące  błędy  w  zupełnie  innych  częściach  programu. 
Dlatego  częściej  stosowana  -  zwłaszcza  w  dużych  projektach  -  jest  metoda 
stopniowej  integracji  i  testowania  coraz  większych  grup  jednostek,  prowadząca  na 
końcu do zbudowania całości systemu. 

Stopniową integrację programu można prowadzić w sposób  

 

wstępujący lub  

 

zstępujący.  

background image

Strategia  wstępująca  zaczyna  od  łączenia  jednostek  najniższego  poziomu  w 

większe  komponenty,  te  w  jeszcze  większe  aż  do  osiągnięcia  poziomu  całego 
programu.  Zaletą  takiego  podejścia  jest  zredukowanie  liczby  koniecznych  do 
opracowania  namiastek  -  w  każdym  kroku  zarówno  testowany  komponent,  jak  i 
wszystkie  wywoływane  przez  niego  podprogramy  są  już  dostępne.  Wadą  jest  brak 
dostępności interfejsu użytkownika, ulokowanego często w głównej części programu, 
w  początkowych  krokach  integracji.  Strategia  zstępująca  przebiega  w  odwrotnym 
kierunku.  Do  programu  głównego  dołącza  się  podprogramy  wywoływane,  aż  do 
poziomu najprostszych jednostek. Ta strategia wymaga opracowania większej liczby 
namiastek,  ale  w  zamian  zapewnia  dostęp  do  interfejsu  użytkownika  od  samego 
początku. 

W  większości  praktycznych  przypadków  testowanie  integracyjne  przeprowadza 

się  stopniowo,  łącząc  elementy  strategii  zstępującej  i  wstępującej.  Strategię 
jednoczesnej integracji całości stosuje się bardzo rzadko. 

 
Testowanie systemowe 
Przedmiotem  testowania  systemowego  (system  testing)  jest  całość 

oprogramowania  zintegrowana  i  zainstalowana  w  odpowiednim  środowisku 
wykonawczym.  Celem  testów  jest  sprawdzenie  zgodności  sposobu  działania 
wszystkich  funkcji  oprogramowania  ze  specyfikacją  oraz  weryfikacja  innych 
właściwości  systemu określonych  przez  wymagania  niefunkcjonalne.  Wiarygodność 
wyników  testów  wymaga,  aby  środowisko  testowe  było  jak  najbardziej  zbliżone  do 
przewidywanego  środowiska  pracy  oprogramowania.  Konstrukcja  testów  traktuje 
system jako całość i nie jest nastawiona na wnikanie w jego budowę. 

Specyfikacja  oprogramowania  określająca  dokładnie,  co  oprogramowanie  ma 

robić  i  w  jakim  zakresie  (wydajność,  niezawodność  itp.),  powstaje  w  procesie 
kaskadowym  w  fazie analizy.  W  procesie  iteracyjnym  dokładna  specyfikacja funkcji 
oraz właściwości niefunkcjonalnych powstaje w fazie opracowania. Jeśli projekt jest 
prowadzony  z  użyciem  metod  obiektowych,  to  rolę  specyfikacji  funkcji 
oprogramowania  może  pełnić  systemowy  model  przypadków  użycia.  Wraz  ze 
specyfikowaniem wymaganego zachowania systemu powinien też powstać plan jego 
testowania. Przeprowadzenie testów systemowych, możliwe dopiero po zakończeniu 
integracji  oprogramowania,  tworzy  osobny  etap  procesu  wytwórczego. 

background image

Zaprojektowanie i wykonanie testów nie wymaga znajomości szczegółów konstrukcji 
oprogramowania,  wymaga  natomiast  specjalistycznej  wiedzy  dotyczącej  sposobów 
sprawdzania  właściwości  niefunkcjonalnych.  Z  tego  powodu  etap  testowania 
systemowego realizuje zazwyczaj wyspecjalizowany zespół testujący. Wykryte błędy i 
niezgodności  ze  specyfikacją  są  opisywane  w  raporcie  problemów  testowania  i 
przekazywane deweloperom do usunięcia. 

Etap testowania systemowego składa się zwykle z szeregu odrębnych kroków, w 

których sprawdzane są róże aspekty działania systemu. Szczegółowy wykaz testów 
zależy od dziedziny zastosowania i specyfikacji wymagań. Typowe przykłady testów 
systemu obejmują: 

 

testy  funkcjonalne  (functional  testing),  obejmujące  sprawdzenie 
poprawności  wykonania  wszystkich  funkcji  systemu  (np.  systemowych 
przypadków użycia); 

 

testy  wydajnościowe  (performance  testing),  obejmujące  sprawdzenie 
działania systemu (np. czasu przetwarzania) przy nominalnym obciążeniu; 

 

testy przeciążeniowe (stress testing), sprawdzające zachowanie systemu 
w warunkach przekroczenia założonego obciążenia systemu; 

 

testy  bezpieczeństwa  (security  testing),  których  celem  jest  sprawdzenie 
skuteczności  mechanizmów  ochrony  systemu  przed  nieuprawnionym 
użyciem; 

 

testy 

odporności 

(recovery 

testing), 

sprawdzające 

działanie 

oprogramowania  w  warunkach  awarii,  np.  nagłego  wyłączenia,  restartu 
komputera lub odłączenia sieci; 

 

testy  zgodności  (compatibility  testing),  sprawdzające  możliwość  pracy 
oprogramowania  na  różnych  platformach  (np.  różne  systemy  operacyjne 
lub bazy danych itp.); 

 

testy  dokumentacji  (<documentation  testing),  obejmujące  sprawdzenie 
zgodności działania oprogramowania z opisem zawartym w dokumentacji. 

 
 
Testowanie akceptacyjne 
Testowaniu  akceptacyjnemu  (acceptance  testing)  podlega  oprogramowanie 

stanowiące  przedmiot  dostawy  dla  użytkownika,  zainstalowane  w  docelowym 

background image

środowisku  pracy  lub  w  środowisku  imitującym  docelowe  środowisko  pracy 
oprogramowania. Celem testów jest sprawdzenie zgodności działania z wymaganiami 
i potrzebami użytkownika. Forma testów może być podobna do testów systemowych, 
jednak  proces  testowania  nie  jest  już  zorientowany  na  znajdowanie  i  usuwanie 
defektów,  lecz  raczej  na  zademonstrowanie  i  zatwierdzenie  produktu  przez 
użytkownika oraz ewentualne dostrojenie do jego rzeczywistych potrzeb. 

Teoretycznie testy akceptacyjne powinien zawsze przeprowadzać użytkownik. W 

praktyce  jednak  testy  akceptacyjne  przeprowadza  często  wykonawca  pod 
bezpośrednim  nadzorem  użytkownika  lub  zewnętrznej  firmy  działającej  na  jego 
zlecenie. W takim przypadku użytkownik zatwierdza najpierw scenariusze testowania, 
a  później  kontroluje  wiarygodność  przeprowadzenia  testów.  Jeśli  zostaną  wykryte 
błędy  lub  niezgodności  ze  specyfikacją  wymagań,  to  są  one  opisywane  w  raporcie 
problemów i usuwane w określonym umową terminie. 

W  przypadku  systemów  ogólnodostępnych,  które  nie  są  przeznaczone  dla 

konkretnego odbiorcy, testowanie akceptacyjne może przybrać formę kontrolowanej 
eksploatacji  w  siedzibie  wytwórcy  (testy  alfa)  oraz  u  wytypowanych  odbiorców  lub 
dystrybutorów produktu (testy beta). Błędy i niezgodności wykryte podczas obu faz 
testów  są  raportowane  do  wytwórcy  i  usuwane przed ostatecznym  wypuszczeniem 
produktu na rynek. 

Specyfikacja  wymagań  użytkownika,  zapisana  w  umowie  na  opracowanie 

oprogramowania,  jest  zwykle  zbyt  mało  dokładna,  aby  określić  sposób  testowania 
akceptacyjnego.  Dokładniejsza  wersja  specyfikacji  jest  wynikiem  analizy  wymagań 
dokonanej  już  po  zawarciu  umowy  lub  podjęciu  decyzji  o  opracowaniu 
oprogramowania. Jeśli projekt jest prowadzony z użyciem metod obiektowych, to rolę 
specyfikacji  wymagań,  prezentującej  biznesowy  punkt  widzenia  użytkownika,  może 
pełnić biznesowy model przypadków użycia. Scenariusze biznesowych przypadków 
użycia są naturalnymi kandydatami na scenariusze testowania akceptacyjnego. Wraz 
z opracowaniem modelu biznesowych przypadków użycia powinien też powstać plan 
testowania akceptacyjnego. 

Etap testowania akceptacyjnego dzieli się zwykle na kilka odrębnych kroków, w 

których sprawdzane są róże aspekty jego działania, np.: 

 

testy funkcjonalne, sprawdzające dopasowanie funkcji systemu do potrzeb 
procesów biznesowych użytkownika; 

background image

 

testy operacyjne, sprawdzające działanie funkcji wykorzystywanych przez 
administratorów systemu; 

 

testy niefunkcjonalne, podobne lub identyczne z testami systemowymi. 

 
 
 

2. Organizacja procesu testowania 

 
Skuteczne przeprowadzenie testów i usunięcie błędów oprogramowania wymaga 

-  zwłaszcza  w  dużym  projekcie  -  całego  szeregu  działań  przygotowawczych, 
związanych  z  planowaniem,  projektowaniem  i  wykonaniem  testów.  Wynikiem  tych 
działań  są  odpowiednie  dokumenty  planistyczne,  specyfikacje  testów  i  raporty 
testowania.  Przygotowane  tych  dokumentów  i  wdrożenie  ich  w  praktyce  jest 
przedmiotem  procesu  zarządzania  testowaniem,  które  wchodzi  w  skład  procesu 
zarządzania projektem programistycznym. 

Nie  ma  jednej  standardowej  organizacji  procesu  testowania  i  jednego 

standardowego sposobu dokumentowania tego procesu. Różne metody zarządzania 
projektami, a nawet różne projekty, stosują własne rozwiązania, które w dużej mierze 
są pochodną wielkości projektu, konsekwencji ewentualnej awarii oprogramowania i 
posiadanego  budżetu.  W  małych,  kilkuosobowych, projektach testowanie  prowadzą 
często  deweloperzy  tworzący  oprogramowanie.  Proces  testowania  jest  mało 
sformalizowany i ograniczony do niezbędnego minimum. Zaletą takiego podejścia jest 
niski  koszt,  a  wadą  -  ograniczony  zakres  testowania.  W  większych  projektach 
testowaniem - zwłaszcza na wyższych poziomach  - zajmują się niezależne zespoły 
testerów.  Umożliwia  to  użycie  lepszych  metod  i  narzędzi,  zapewnia  bardziej 
wszechstronne  i  wiarygodne  przeprowadzenie  testów,  wymaga  jednak  poniesienia 
dodatkowych  kosztów  związanych  z  organizacją  i  formalnym  dokumentowaniem 
całego procesu. 

Treść  tego  podrozdziału  opisuje  pewien  model  organizacji  testowania,  który 

wyznacza  dominujący  kierunek  [176],  ale  od  którego  istnieją  w  praktyce  liczne 
odstępstwa. 

 

background image

2.1. Planowanie testów 

Podstawowym  dokumentem  planistycznym,  opisującym  organizację  procesu 

testowania, jest plan testów (test plan). Postać tego dokumentu może być w różnych 
projektach  różna  -  w  niektórych  przypadkach  pojedynczy  dokument  opisuje 
testowanie  na  wszystkich  poziomach,  w  innych  plany  testowania  na  różnych 
poziomach  są  opisywane  w  odrębnych  dokumentach.  Jeżeli  testy  jednostkowe  i 
integracyjne  wykonują  deweloperzy,  to  często  nie  tworzy  się  formalnych  planów,  a 
jedynie  rezerwuje  czas  i  zasoby  w  planie  projektu.  W  takim  przypadku plan  testów 
obejmuje  tylko  etapy  testowania  systemowego  i  testowania  akceptacyjnego,  które 
pochłaniają  dużo  czasu  i  które  mogą  być  wykonane  dopiero  po  zakończeniu 
implementacji i integracji oprogramowania. Ze względu na konieczność uzgodnienia 
przebiegu  testowania  akceptacyjnego  z  użytkownikiem  plan  testowania 
akceptacyjnego  jest  często  odrębnym  dokumentem,  którego  wstępna  wersja 
obejmująca  przede  wszystkim  harmonogram  testowania  jest  często  zapisana  w 
umowie. 

Treść  planu  testów  opisuje  zakres  testów,  strategię  testowania  i  raportowania 

błędów, niezbędne zasoby i harmonogram działań. 

Definicja  zakresu  obejmuje  identyfikację  testowanych  produktów,  określenie 

wymagań  (właściwości),  które  będą  testowane,  oraz  jawne  wskazanie  wymagań, 
które testowane nie będą. 

Strategia testowania określa środki, które zostaną użyte do zapewnienia należytej 

jakości  testowania  różnych  grup  wymagań.  Mieści  się  w  tym  wskazanie  działań  i 
metod  testowania  (np.  metody  pomiaru  wydajności),  zdefiniowanie  kryteriów 
zakończenia testów (np. z wykorzystaniem metryk opisanych w podrozdziale 3) oraz 
określenie  kryteriów  oceny  pozytywnego  lub  negatywnego  wyniku  testów 
oprogramowania  lub  jego  komponentów.  Proste  kryteria  oceny  wyniku  testów 
polegają  na  klasyfikacji  błędów  na  kategorie  odzwierciedlające  stopień  ich 
szkodliwości  -  np.:  awarie,  błędy  poważne,  błędy  drobne  -  a  następnie  określeniu 
dopuszczalnej liczby błędów każdego rodzaju ujawnionych podczas testów. Bardziej 
zaawansowane  metody  korzystają  z  obliczeń  probabilistycznych  umożliwiających 
określenie  niezawodności  oprogramowania,  wyrażonej  w  postaci  oczekiwanej 
wartości  czasu  między  wystąpieniami  dwóch  kolejnych  błędów.  Opis  strategii 

background image

testowania  powinien  być  na  tyle  dokładny,  aby  umożliwić  identyfikację  głównych 
zadań oraz ocenę zasobów i czasu potrzebnego do ich wykonania. 

Zasoby  niezbędne  do  przeprowadzenia  testów  obejmują  środowisko  testowe, 

zespół lub zespoły wykonawców o różnych kwalifikacjach oraz wymaganą przestrzeń 
biurową.  Środowisko  testowe  obejmuje  system  komputerowy  dedykowany  do 
prowadzenia  testów  wraz  z  oprogramowaniem  wspomagającym.  Planując  proces 
testowania, trzeba określić konieczne do wykonania zakupy, zakres niezbędnych do 
wykonania  prac  instalacyjnych  i  konfiguracyjnych  oraz  potrzebę  wytworzenia 
sterowników  i  namiastek  testowych.  Jeśli  testowanie  ma  być  przeprowadzone  na 
danych  pochodzących  z  systemu  produkcyjnego,  to  plan  testów  powinien  określić 
metodę  pozyskania  i  przeniesienia  danych.  Wielkość  i  sposób  organizacji  zespołu 
testującego  zależą  od  wielkości  projektu.  W  małych  projektach  wystarczy  wskazać 
osoby  przydzielone  do  testowania.  W  dużych  projektach  istnieje  potrzeba 
zdefiniowania  struktury  organizacyjnej,  podporządkowanej  kierownikowi  projektu  i 
obejmującej projektantów i wykonawców testów (rys. 2). Poza wskazaniem potrzeb 
plan  testowania  powinien  wyraźnie  określić  odpowiedzialność  za  dostarczenie 
testowanych  programów,  przygotowanie  środowiska,  zarządzanie,  projektowanie  i 
wykonanie testów oraz usunięcie błędów. 

 

 

 

Rysunek 2. Organizacja zespołu testującego 

 
Warunkiem  rozpoczęcia  testowania  jest  wytworzenie  testowanego  produktu. 

Czas  przeznaczony  na  testowanie  zależy  od  wielkości  oprogramowania,  stopnia 
automatyzacji  testów  oraz  liczby  jednocześnie  pracujących  testerów.  Dlatego 
harmonogram  testowania  jest  ściśle  związany  z  harmonogramem  opracowania 
oprogramowania  oraz  z  wielkością  przydzielonych  do  projektu  zasobów. 
Najtrudniejszym  zadaniem  podczas  tworzenia  harmonogramu  jest  oszacowanie 
pracochłonności  testowania.  Znając  oszacowanie  pracochłonności,  można  albo 

background image

narzucić z góry czas testowania i dobrać odpowiednią wielkość zespołu, albo przyjąć 
pewną wielkość zespołu i obliczyć niezbędny czas trwania testów. 

 
 

2.2. Przygotowanie testów 

Skuteczne  przeprowadzenie  testów  oprogramowania  wymaga  zaprojektowania 

takiego  zestawu  testów,  który  zapewni  kompletne  i  wiarygodne  sprawdzenie 
produktu,  zgodnie  ze  strategią  określoną  w  planie  testowania.  Najważniejszym 
dokumentem  projektowym  opisującym  planowane  testy  oprogramowania  jest 
specyfikacja testów (test specification). Treścią tego dokumentu jest lista przypadków 
testowych wraz ze wskazaniem wymagań (np. obecności pewnych danych w bazie 
danych)  lub  ograniczeń  ich  wykonania.  Jeśli  wykonanie  przypadku  testowego 
wymaga  określonej  sekwencji  działań  testera,  np.  wypełnienia  pól  ekranu, 
zaznaczenia pól wyboru i kliknięcia przycisku akceptacji, to sekwencja tych czynności, 
opisana  w  specyfikacji  testów,  tworzy  scenariusz  przypadku  testowego  (test  case 
scenario). 

Struktura  i  postać  specyfikacji  testów  zależą  od  wielkości  projektu.  W  małych 

projektach specyfikacja testów może liczyć kilka kartek zawierających opis wszystkich 
przypadków  testowych.  W  takich  przypadkach  specyfikacja  testów  jest  niekiedy 
włączana w skład planu testów. W projektach dużych specyfikacja testów może mieć 
postać  kilku  odrębnych  dokumentów  poświęconych  testowaniu  różnych  obszarów 
funkcjonalnych  oraz  różnych  właściwości  niefunkcjonalnych.  Co  więcej,  w  dużych, 
sformalizowanych projektach bezpośrednie przejście od planu do specyfikacji testów 
jest niejednokrotnie zbyt trudne do wykonania. W takich przypadkach opracowuje się 
często  dodatkowy  dokument  projektu  testów  (test  design),  który  wiąże  strategię 
testowania,  opracowaną  w  planie  testów,  z  dokładnym  opisem  przypadków 
testowych,  zapisanym  w  specyfikacji  testów.  Powiązanie  dokumentacji  testów  z 
dokumentacją projektu oprogramowania jest pokazane na rys. 3. 

background image

 

Rysunek 3. Relacja dokumentów projektowych i testowych [176] 

 
Specyfikacja  testów  jest  dokumentem  projektowym  procesu  testowania, 

opisującym przypadki testowe w takiej kolejności i w taki sposób, aby umożliwić łatwe 
sprawdzenie  kompletności  testów.  Na  przykład,  w  specyfikacji  testów  systemu 
wspomagającego działanie urzędu administracji publicznej można opisywać kolejno: 
testy  wszystkich  metod  wprowadzania  dokumentów,  testy  wszystkich  sposobów 
otwierania  sprawy  petenta,  testy  wszystkich  form  kontroli  itd.  Nie  jest  to  kolejność 
wygodna  do  przeprowadzenia  testów.  Ponieważ  wykonanie  wcześniejszej  fazy 
obsługi  tej  samej  sprawy  (np.  wprowadzenie  dokumentu)  warunkuje  możliwość 
wykonania  fazy  późniejszej  (np.  kontroli  tego  dokumentu),  więc  wygodniej  jest 
prowadzić testy w kolejności zgodnej z logiką procesu biznesowego, wspomaganego 
przez  oprogramowanie.  Tę  kolejność  oraz  sposób  przeprowadzenia  testów  opisuje 
odrębny dokument nazywany procedurą testowania (test procedure). 

Procedura  testowania  określa  początkowy  stan  systemu  w  chwili  rozpoczęcia 

testowania  oraz  listę  zestawów  testów  do  wykonania  (rys.  4).  Definicja  zestawu 
testów zawiera listę scenariuszy przypadków testowych, wykonywanych w ustalonej 
kolejności, oraz listę zbiorów danych testowych używanych podczas wykonania tych 
scenariuszy. Każdy scenariusz przypadku testowego składa się z sekwencji kroków, z 
których  każdy  obejmuje  jedną,  dobrze  określoną  czynność.  W  przykładowej 
procedurze  testowania  jest  nią  wywołanie  wskazanej  funkcji  menu,  wybranie 
wskazanej opcji lub wypełnienie pól ekranu wartościami pobranymi z przygotowanego 
zbioru danych testowych. 

Zbiory  danych  testowych  mogą  mieć  postać  tabel  wypełnionych  wartościami 

danych wprowadzanych podczas wykonania scenariusza testowego, dołączonych do 
dokumentu procedury testowania. Częściej jednak są one przekazywane testerom w 
postaci  zbioru  danych  zapisanego  na nośniku  maszynowym.  Procedura  testowania 

background image

uzupełniona zbiorami danych testowych oraz opisem oczekiwanych wyników tworzy 
dokładną  instrukcję  wykonania  testów,  która  nie  wymaga  żadnych  dodatkowych 
dokumentów wyjaśniających. 

Procedura testowania funkcjonalności płatności obszarowych 

1. 

Początkowy stan systemu: 

 

.... opis konfiguracji systemu, sieci i bazy danych 

 

2. 

Przebieg wykonania (zestawy testów): 

 

Z-1 Wprowadzenie i kontrola danych wniosku 

 

Z-2 Weryfikacja treści wniosku 

 

Z-3 Naliczenie płatności obszarowej 

3. 

Definicje zestawów testów 

 

Z-1 Wprowadzenie i kontrola danych wniosku (przypadki testowe): 

 

P-1 Przyjęcie dokumentu wniosku (zbiory danych testowych D-1, D-2) 

 

P-2 Wprowadzenie danych wniosku (zbiory danych testowych D-1, D-2) 

 

P-3 Zatwierdzenie danych wniosku 

 

P-4 Przeprowadzenie kontroli danych 

 

Z-2 Weryfikacja treści wniosku 

 

Z-3 Naliczenie płatności obszarowej 

4. 

Scenariusze przypadków testowych 

 

P-1 Przyjęcie dokumentu wniosku 

 

1. Wybranie funkcji Przyjęcie dokumentu 

 

2. Zaznaczenie pola Wniosek obszarowy 

 

3. Wybranie funkcji Utworzenie sprawy 

 

4. Wprowadzenie opisu dokumentu (data, nadawca) 

 

 Wybranie opcji Zatwierdzenie sprawy 

 

P-2 Wprowadzenie danych wniosku 

 

Rysunek 4. Procedura testowania jednej z funkcjonalności systemu wspierającego dopłaty rolne 

 
Warto zwrócić uwagę, że poszczególne przypadki testowe nie są wymienione w 

procedurze testowania w sposób jawny (jest ich zbyt dużo). Zamiast tego procedura 

background image

definiuje scenariusze przypadków użycia oraz zbiory danych testowych. Pojedynczy 
przypadek testowy odpowiada jednemu wykonaniu scenariusza przypadku testowego 
z  użyciem  konkretnych  danych  ze  zbioru  danych  testowych  przypisanych  do  tego 
scenariusza. 

 
 

2.3. Testowanie a usuwanie defektów 

Błędem  jest  każdy  nieprawidłowy,  czyli  niezgodny  ze  specyfikacją,  wynik 

działania programu. Przyczyną błędów są tkwiące w programie defekty. Celem etapu 
testowania  jest  wykrycie  błędów  działania  programu,  a  następnie  lokalizacja  i 
usunięcie  powodujących  te  błędy  defektów.  Czynności  wykrywania  błędów 
(testowanie) oraz usuwania defektów (poprawianie programu) są różne i mogą być 
różnie usytuowane w czasie. 

Najprostszy  sposób  działania  polega  na  znajdowaniu  i  usuwaniu  defektu 

natychmiast  po  wykryciu  błędu  -  jest  to  postępowanie  naturalne  dla  dewelopera 
samodzielnie  testującego  swój  program.  Nie  jest  to  jednak  strategia  dobra  dla 
zespołu, w którym prace powinny przebiegać równolegle. Można równolegle testować 
program na kilku stanowiskach i wykrywać w tym czasie różne błędy, ale nie można 
równolegle  tych  błędów  poprawiać  -  takie  działanie  mogłoby  doprowadzić  do 
powstania  kilku  różnych  wersji  programu,  z  których  każda  zawierałaby  różne 
poprawki.  Dlatego  zwykle  przyjmuje  się  inny  sposób  działania,  zgodnie  z  którym 
najpierw  testuje  się  program  w  serii  testów,  rejestrując  przy  tym  błędy,  a  potem 
analizuje się kod programu, odnajdując i usuwając defekty. 

Wszystkie  niezgodności  wyników  z  oczekiwaniami,  zaobserwowane  podczas 

wykonywania  testów,  są  zapisywane  w  raporcie  problemów  (test  incident  report). 
Nazwa  tego  dokumentu  podkreśla  fakt,  że  nie  każda  niezgodność  wyniku  z 
oczekiwaniem  musi  być  błędem  programu.  Błędy  mogą  też  tkwić  w  testach,  w 
dokumentacji  programu  i  w  dokumentacji  testów.  Mylić  mogą  się  także  testerzy. 
Dlatego każdy wykryty i opisany w raporcie problem musi być poddany analizie, której 
wynikiem  jest  kwalifikacja  problemu.  Tylko  problemy  zakwalifikowane  jako  błędy 
programu są przekazywane deweloperom do usunięcia (rys. 5). 

 
 

background image

 

Rysunek 5. Testowanie, analiza problemów i usuwanie błędów 

 
Po  wykonaniu  serii  testów  i  wprowadzeniu  poprawek  powstaje  kolejna  wersja 

programu, która jest poddawana podwójnemu sprawdzeniu: 

 

czy wszystkie dotychczas działające funkcje programu działają nadal (testy 
regresji), 

 

czy wszystkie wykryte błędy zostały rzeczywiście usunięte (retesty). 

 
Zestaw testów regresji (regression test) obejmuje te testy, które były wykonywane 

bezbłędnie przed rozpoczęciem wprowadzania poprawek. Zestaw retestów obejmuje 
te  testy,  których  wyniki  zostały  zakwalifikowane  jako  błędy.  Błędne  wyniki 
którejkolwiek  z  tych  dwóch  grup  testów  powodują  ponowne  odesłanie  produktu  do 
poprawek.  Poprawne  wyniki  wszystkich  testów  kończą  bieżący  cykl  testowania  i 
otwierają  drogę  do  kolejnych  serii  testów  (rys.  6).  Etap  testowania  kończy  się  po 
spełnieniu kryteriów zakończenia sformułowanych w planie testów. 

 

Cykl testowania 

Kolejny cykl 

Seria testów 

Poprawki 

Testy regresji 

Retesty 

Koleina  seria 

testów 

  ► 

Rysunek 6. Testowanie i usuwanie defektów programu 

 
 

3. Metryki 

 
Testowanie oprogramowania  jest  długotrwałym  procesem,  od  którego  w dużym 

stopniu  zależy  jakość finalnego  produktu  i  który  pochłania  znaczną  część  zasobów 
projektu.  Aby  móc  efektywnie  planować  i  zarządzać  wykonaniem  tego  procesu, 

background image

potrzebny jest jakiś sposób pomiaru jakości testów oraz sposób pomiaru postępu prac 
w  czasie  trwania  procesu  testowania.  Narzędziem  pomiaru  są  metryki  testowania, 
czyli  ilościowe  miary  odzwierciedlające  różne  cechy  zaprojektowanych,  lub  już 
wykonanych, testów. Stworzenie możliwości  oceny jakości testów otwiera drogę do 
planowania  jakości  testowania  i  zapobiegania  przypadkom  niewiarygodnej  lub 
niedostatecznej weryfikacji programu. 

Jedną  z  najczęściej  stosowanych  metod  pomiaru  i  poprawy  jakości  testów  jest 

analiza  pokrycia  kodu  (code  coverage  analysis).  Celem  tej  analizy  jest  ilościowa 
ocena  kompletności  testów,  znalezienie  obszarów  kodu,  które  nie  są  sprawdzane 
przez testy, oraz wykrycie nadmiarowych przypadków testowych, które nie poprawiają 
jakości  testowania,  a  pochłaniają  czas  i  zasoby.  Konsekwencją  negatywnej  oceny 
może  być  zaprojektowanie  dodatkowych  przypadków  testowych  obejmujących 
sprawdzenie pominiętych obszarów programu. 

Koncepcyjnym  narzędziem  pomiaru  są  metryki  pokrycia  kodu  (code  coverage 

metrics), służące do określenia stosunku obszaru tej części programu, która została 
poddana  testom,  do  całości  programu.  Liczbowa  wartość  metryki  może  być 
wykorzystana  jako  miara  jakości  zestawu  testów  -  tym  lepsza,  im  bliższa  wartości 
pełnego pokrycia kodu (100%). Przyrost wartości tej metryki w okresie wykonywania 
testów  może  stać  się  miarą  postępu  procesu  testowania.  Metryki  pokrycia  kodu 
znajdują zastosowanie przede wszystkim na poziomie testowania jednostkowego. 

Podobną w konstrukcji metodę można wykorzystać do  analizy stopnia pokrycia 

wymagań  testami  funkcjonalnymi.  Celem  analizy  jest  ilościowa  ocena  stopnia 
kompletności  testowania  wymagań  funkcjonalnych  oraz  znalezienie  obszarów 
specyfikacji  wymagań,  które  nie  są  sprawdzane  przez  testy.  Narzędziem  pomiaru 
kompletności testów są odpowiednie metryki, oceniające stosunek liczby zestawów i 
przypadków testowych do liczby wymagań zdefiniowanych w sposób określony przez 
stosowaną metodę analizy. Metryki pokrycia wymagań znajdują zastosowanie przede 
wszystkim na poziomie testowania systemowego lub testowania akceptacyjnego. 

Wykorzystanie metryk pokrycia nie jest jedynym sposobem oceny jakości procesu 

testowania. Prócz nich stosuje się także metryki oparte na bezpośrednim pomiarze 
liczby wykonanych przypadków testowych, liczby wykrytych błędów lub liczby błędów 
usuniętych.  Jeszcze  inna,  szybko  rozwijająca  się  grupa  metod  wykorzystuje 

background image

eksperymentalne  sposoby oceny efektywności  wykrywania błędów  przez  testy oraz 
szacowania liczby niewykrytych błędów, jakie jeszcze pozostały w programie. 

 
 
 

3.1. Metryki pokrycia kodu 

Analiza  pokrycia  kodu  jest  elementem  metody  testowania  „białej  skrzynki", 

zgodnie  z  którą  do  projektowania  i  oceniania  jakości  testów  wykorzystuje  się 
znajomość  wewnętrznej  struktury  programu.  Słabością  tego  podejścia  jest  brak 
jednolitej definicji pokrycia, prowadzący do powstania różnych metryk pokrycia kodu, 
oceniających  jakość  testów  w  stosunku  do  różnych  aspektów  programu.  Istotną 
zaletą wszystkich metryk pokrycia kodu jest łatwość interpretacji wartości tych metryk, 
która może zmieniać się w zakresie od 0 do 100%. 

 
Pokrycie bloków instrukcji 
Blokiem  jest  ciąg  instrukcji  programu,  niezawierający  instrukcji  powodujących 

rozgałęzienie  alternatywnych  dróg  wykonania  -  tzn.  instrukcji 

if  switch,  for  itp. 

Wartością  metryki  pokrycia  bloków  instrukcji  (basic  block  coverage)  jest  stosunek 
liczby bloków przetestowanych do liczby wszystkich bloków programu. Na przykład, 
następujący  fragment  programu  w  języku  C  zawiera  dwa  bloki  instrukcji, 
odpowiadające dwóm gałęziom instrukcji if 

 
if ( a!=0 ) 
x = -b/a; 
printf("x=%f\n",x); 
else 
printf("Niepoprawne dane\n"); 
 
Pełne  pokrycie  bloków  instrukcji  tego  fragmentu  programu  wymaga  użycia  co 

najmniej dwóch przypadków testowych, z których każdy spowoduje wykonanie jedne 
gałęzi instrukcji if. Jeden przypadek testowy zapewni tylko 50% pokrycia. 

Odmianą  metryki  pokrycia  bloków  jest  metryka  pokrycia  instrukcji  kodu,  które 

wartością  jest  stosunek  liczby  przetestowanych  instrukcji  do  liczby  wszystkich 
instrukcji testowanej jednostki programu. 

background image

Podstawowymi  zaletami  obydwu  metryk  są  intuicyjna  zrozumiałość,  prostota 

pomiaru oraz możliwość zastosowania wprost do wynikowego kodu programu, a nic 
tylko  do  kodu  źródłowego.  Zasadniczą  wadą  jest  słabe  odzwierciedlenie  jakości 
sprawdzania  warunków.  Na  przykład,  każdy  przypadek  testowy  z  wartością  b  =  C 
zapewni pełne 100% pokrycia instrukcji programu: 

float b,a = 0; 
if ( b==0 ) a = 1; 
x = b/a; 
ale tylko test z wartością b != 0 pozwoli wykryć błąd prowadzący do zatrzymania 

programu  z  powodu  próby  dzielenia  przez  zero.  Metryka  pokrycia  bloków  nie 
odzwierciedla też w żaden sposób jakości sprawdzania różnych wariantów obliczania 
złożonych warunków instrukcji if ani warunków zakończenia pętli programu. 

 
Pokrycie decyzji 
Decyzją  w  metryce  pokrycia  decyzji  (decision  coverage)  jest  każda  możliwa 

wartość  warunku  w  instrukcji  powodującej  rozgałęzienie  programu,  również  w 
instrukcji  switch.  Wartością  metryki  jest  stosunek  liczby  przetestowanych  wyjść  z 
instrukcji rozgałęziających do liczby wszystkich wyjść z tych instrukcji. Na przykład, 
ostatni  program  zawiera  jedną  instrukcję  if  której  warunek  może  przyjąć  jedną  z 
dwóch  wartości  true  lub  false,  kierując  wykonanie  na  jedną  z  dwóch  różnych  dróg 
programu  (rys. 7a). Pełne pokrycie decyzji  tego  fragmentu  programu  wymaga  więc 
użycia  co  najmniej  dwóch  przypadków  testowych,  z  których  każdy  spowoduje 
obliczenie innej wartości warunku. Program pokazany w postaci sieci działań na rys. 
7b  zawiera  dwie  instrukcje  warunkowe.  Przetestowanie  wszystkich  decyzji  tego 
programu  wymaga  wykonania  trzech  przypadków  testowych,  z  wartościami  danych 
wejściowych: delta>0, delta=0 i delta<0, które spowodują przejście wykonania przez 
każde wyjście obydwu instrukcji warunkowych. 

Metryka pokrycia decyzji wymaga zwykle większej liczby przypadków testowych 

do  pełnego  przetestowania  programu  niż  metryka  pokrycia  bloków  instrukcji.  W 
zamian za to zapewnia nie gorsze sprawdzenie bloków i lepsze sprawdzenie sposobu 
testowania warunków. Wadą tej metryki jest brak wrażliwości na sposób testowania 
warunków złożonych, które nie w każdym przebiegu programu są obliczane do końca. 
Na przykład, następujący fragment programu w języku C zawiera warunek złożony, 

background image

którego  ostatni  człon  będzie  obliczony  tylko  wtedy,  gdy  dwa  pierwsze  nie  określą 
wartości warunku: 

if ( a>0 || ( b>0 && fun(b)>0 ) ) printf("Ok\n"); 
 
Tak więc dwa przypadki testowe z wartościami danych wejściowych np. takich: 
a=5, b=3 
a=0, b=-2 
spowodują obliczenie wartości warunku równej true (pierwszy test) i fase (drugi 

test), co zapewni 100% pokrycia decyzji bez wywołania funkcji 

fun. 

 

 

 

Rysunek 7. Sieci działań ilustrujące drogi przejścia i decyzje programu 

 
Pokrycie ścieżek 
Ścieżką  jest  każda  sekwencja  instrukcji  prowadząca  od  początku  do  końca 

programu.  Wartością  metryki  pokrycia  ścieżek  (path  coverage)  jest  stosunek  liczby 
ścieżek  sprawdzonych  w  testach  do  liczby  wszystkich  ścieżek  istniejących  w 
programie. 

Zgodnie  z  tą  definicją  niekompletne  obliczanie  warunków  złożonych  przez 

kompilatory niektórych języków - np. C, C++ i Javy - tworzy nowe ścieżki wykonania, 
które  nie  są  jawnie  pokazane  w  tekście  programu.  Liczba  wszystkich  ścieżek 
wykonania  warunków  złożonych  odpowiada  liczbie  wszystkich  wykonalnych 
kombinacji  wartości  warunków,  z  których  jest  zbudowany  warunek  złożony.  W  ten 
sposób fragment programu podany powyżej zawiera cztery możliwe ścieżki. 

1.  Obliczenie a>0, po czym wydruk Ok. 
2.  Obliczenie a<0 i b>0, po czym wydruk Ok. 
3.  Obliczenie a<0 i b<0 i f un (b )>0, po czym wydruk Ok. 
4.  Obliczenie a<0 i b<0 i fun (b )<0, brak wydruku. 

background image

Dwa poprzednie przypadki testowe sprawdzają tylko dwie ścieżki, co zapewnia 

50%  pokrycia  ścieżek  programu.  Pełne  pokrycie  ścieżek  tego  programu  wymaga 
wykonania  aż  czterech  testów.  Metryka  pokrycia  ścieżek  wymaga  zwykle  większej 
liczby  testów  do  uzyskania  pełnego  pokrycia  niż  inne  metryki,  co  zapewnia  lepszą 
jakość testowania. 

Z drugiej strony trudnym problemem dla praktycznego wykorzystania tej metryki 

są pętle, których obecność wprowadza bardzo dużą, a czasem nieskończoną, liczbę 
możliwych ścieżek przejścia programu. Wykonanie programu z dwoma obiegami pętli 
przebiega po innej ścieżce niż wykonanie z trzema, czterema itd. obiegami pętli. Z 
tego  powodu  metryka  pokrycia  ścieżek  bywa  stosowana  w  praktyce  w 
zmodyfikowanej wersji, w której rozważa się tylko ograniczoną liczbę obiegów pętli. 

Przytoczone  tu  metryki  pokrycia  nie  wyczerpują  wszystkich  możliwości.  Istnieje 

szereg  innych  metryk,  których  konstrukcja  bierze  pod  uwagę  np.  stopień  pokrycia 
wywołań  funkcji,  dróg od  przypisania  wartości  zmiennej  do  odczytania  tej  wartości, 
odwołań  do  komórek  tablic  i  wiele  innych.  Głównym  obszarem  zastosowania  tych 
metryk jest planowanie i ocena testów jednostkowych oprogramowania wpływającego 
na  bezpieczeństwo  ludzi.  Na  przykład,  pewien  wariant  metryki  pokrycia  dróg 
programu,  znany  pod  nazwą  kombinowanej  metryki  pokrycia  warunków  i  decyzji 
(modified  condition/decision  coverage),  jest  wymagany  do  oceny  testowania 
oprogramowania używanego w lotnictwie [172]. 

 
 

3.2. Metryki pokrycia wymagań 

Analiza pokrycia wymagań jest elementem metody testowania „czarnej skrzynki", 

w  której  nie  korzysta  się  z  wiedzy  dotyczącej  wewnętrznej  struktury  programu. 
Zarówno projekt testów, jak i ocena jakości testowania odwołują się w tym podejściu 
do  specyfikacji  wymagań  traktowanej  jako  wzorzec  poprawnego  zachowania 
programu.  Miarą  jakości  testów  jest  stopień  pokrycia  wymagań  przypadkami 
testowymi.  Zaletą  takiego  podejścia  jest  bezpośrednie  skojarzenie  oceny  jakości 
testów  z  oceną  stopnia  spełnienia  wymagań,  prowadzące  do  wysokiej 
akceptowalności  wyników  oceny  przez  użytkowników.  Wadą  metody  jest  brak 
jednolitej definicji pokrycia wymagań oraz brak standaryzacji zarówno samych metryk, 
jak i ich nazewnictwa. 

background image

 
Pokrycie wymagań 
Wartością  metryki  pokrycia  wymagań  (requirements  coverage)  jest  stosunek 

liczby  przetestowanych  wymagań  do  liczby  wszystkich  wymagań  zapisanych  w 
specyfikacji.  Liczba  przypadków  testowych  niezbędnych  do  przetestowania 
pojedynczego wymagania zależy od jego charakteru i stopnia złożoności. 

Sposób rozumienia pojęcia „wymagania" w tej definicji zależy od metody przyjętej 

do  określania  wymagań.  Jeżeli  wymagania  są  określone  tekstowo,  w  postaci 
wypunktowanej  listy  wymagań,  to  za  wymaganie  można  uznać  każdy  punkt  listy. 
Słabością tego określenia jest niska precyzja i potencjalny brak rozłączności różnych 
punktów  listy.  Zaletą  jest  możliwość  uwzględnienia  w  wartości  metryki  zarówno 
wymagań  funkcjonalnych,  jak  i  niefunkcjonalnych.  Jeśli  modelem  wymagań  jest 
hierarchia  funkcji,  to  za  wymaganie  można  uznać  każdą  funkcję  położoną  na 
najniższym  poziomie  hierarchii.  Jeśli  wymagania  są  modelowane  w  postaci 
przypadków  użycia,  to  wymaganiem  jest  każdy  zdefiniowany  scenariusz  przypadku 
użycia. 

 
Pokrycie błędów 
Metryki  pokrycia  wymagań  koncentrują  się na  kontroli  poprawnego  zachowania 

programu. Dla stabilności aplikacji ważne jest również zachowanie w przypadku błędu 
- pomyłki operatora, awarii urządzenia peryferyjnego, błędnych danych wejściowych 
lub wewnętrznego błędu programu. Na ogół oprogramowanie wykrywa i sygnalizuje 
przynajmniej część takich sytuacji za pomocą odpowiedniego komunikatu błędu. Lista 
wykrywanych  błędów  powinna  być  jawnie  podana  w  dokumentacji  programu. 
Wartością  metryki  pokrycia  błędów  (error  coverage)  jest  stosunek  liczby  błędów, 
których  wykrycie  zademonstrowano  podczas  testów,  do  liczby  wszystkich  błędów 
wykrywanych zgodnie z dokumentacją programu. 

 
Testowanie przypadków użycia 
Specyfikacja  oprogramowania  w  postaci  modelu  przypadków  użycia  silnie 

wspiera  proces  projektowania  testów  akceptacyjnych.  Bardzo  często  istnieje 
bezpośrednia odpowiedniość między biznesowymi przypadkami użycia a zestawami 
testów  wchodzących  w  skład  procedury  testowej  oraz  między  systemowymi 

background image

przypadkami  użycia  a  przypadkami  testowymi.  W  takiej  sytuacji  celowe  może  być 
obliczenie następujących metryk: 

 

pokrycia biznesowych przypadków użycia zestawami testów, 

 

pokrycia  systemowych  przypadków  użycia  scenariuszami  przypadków 
testowych, 

 

pokrycia  scenariuszy  systemowych  przypadków  użycia  przez  przypadki 
testowe. 

 
Przytoczone metryki można obliczyć albo zbiorczo, w postaci wartości średnich - 

np. stosunek liczby wszystkich scenariuszy przypadków testowych wymienionych w 
procedurze  testowej  do  liczby  wszystkich  przypadków  użycia,  albo  odrębnie  dla 
każdego  przypadku  użycia.  Niezależnie  od  przyjętej  metody  liczenia  zbyt  niskie 
wartości metryk świadczą o niskiej jakości testowania. Wartością graniczną dla oceny 
liczby przypadków testowych, niezbędnych do przetestowania przypadku użycia, jest 
liczba jego scenariuszy. Jeżeli liczba przypadków testowych jest mniejsza od liczby 
scenariuszy przypadku użycia, to znaczy, że pewne scenariusze zostały w procesie 
testowania pominięte. 

 
 

3.3. Inne metryki 

Testowanie  jest  końcową  czynnością  całego  procesu  wytwórczego,  lub  jego 

kolejnej iteracji, wykonywaną po implementacji programu. Dlatego przebieg procesu 
testowania  -  w  tym  czas  trwania  oraz  liczba  i  rodzaj  wykrytych  błędów  -  zależy  w 
dużym stopniu nie tylko od jakości testów, ale także od jakości wytworzonego kodu. 
Ocena  obydwu  tych  czynników  jest  ważnym  elementem  wspomagającym  działanie 
kierownika projektu. Z tego powodu podczas trwania testów oblicza się często szereg 
różnych  metryk  umożliwiających  pomiar  i  ocenę  zarówno  procesu  testowania  i 
usuwania błędów, jak i jakości testowanego kodu. 

 
Liczba wykrytych defektów 
Wartość  tej  metryki,  rejestrowana  regularnie  podczas  trwania  testów  i 

obserwowana systematycznie podczas różnych projektów, pozwala ocenić: 

background image

 

początkową  jakość  kodu  wytworzonego  przez  programistów  i 
deweloperów, 

 

przyrost tej jakości następujący w wyniku usuwania błędów, 

 

efektywność różnych metod i etapów testowania. 

Typowy przebieg zmiany łącznej liczby defektów kodu wykrytych podczas trwania 

testów,  pokazany  na  rys.  8,  dzieli  się  na  trzy  wyraźnie  różne  okresy.  Okres 
rozruchowy, o niewielkiej liczbie wykrytych defektów, okres środkowy, w którym liczba 
wykrytych  defektów  szybko  przyrasta,  oraz  okres  stabilizacji  oprogramowania,  w 
którym  na  skutek  usunięcia  większości  defektów  liczba  wykrytych  defektów  niemal 
przestaje  wzrastać.  Osiągnięcie  stadium  stabilizacji  liczby  wykrytych  defektów  jest 
jednym z ważnych kryteriów zakończenia testów. 

 

 

Rysunek 8. Łączna liczba defektów wykrytych podczas testowania Liczba defektów komponentu 

 
Wartości  tej  metryki,  równe  łącznej  liczbie  defektów  wykrytych  podczas 

testowania  poszczególnych  komponentów  oprogramowania,  mają  dwojakie 
znaczenie.  Po  pierwsze,  duża  liczba defektów  komponentu,  testowanego  podobnie 
jak  wszystkie  inne  komponenty,  może  świadczyć  o  jego  wysokiej  złożoności  lub  o 
niskiej  jakości  jego  kodu.  Porównanie  różnych  komponentów  może  więc  pomóc  w 
ustaleniu  komponentów  ryzykownych,  wymagających  specjalnej  uwagi  w  procesie 
integracji  oraz  podczas  późniejszej  konserwacji  oprogramowania.  Po  drugie,  duża 
liczba  defektów  kodu  może  świadczyć  o  niskiej  jakości  pracy  lub  przeciążeniu 
opracowujących ten komponent deweloperów. To z kolei może pomóc kierownikowi 
projektu w podjęciu decyzji o przemieszczeniu zasobów. 

background image

Pewnym wariantem tej i poprzedniej metryki jest zliczanie defektów w rozbiciu na 

poszczególne testy lub zestawy testów. Porównanie wyników pozwala wybrać testy 
wykrywające  najwięcej  defektów.  Może  to  pomóc  w  konstruowaniu  zbioru  testów 
regresji  lub  zbioru  testów  zaufania  (smoke  tests),  używanych  do  szybkiego 
sprawdzenia poprawności programu podczas konserwacji. 

 
Częstość defektów 
Metryka  częstości  defektów  należy  do  najpopularniejszych  i  najczęściej 

stosowanych  miar  oceny  jakości  kodu  programu  przeznaczonego  do  zastosowań 
komercyjnych. Konstrukcja tej metryki opiera się na intuicyjnym założeniu, że liczba 
defektów  programu  rośnie  wraz  ze  wzrostem  rozmiaru  jego  kodu.  Aby  zapewnić 
porównywalność  wyniku  niezależnie  od  wielkości  programu,  przyjmuje  się,  że 
wartością metryki jest stosunek liczby defektów do liczby wierszy kodu programu. Tak 
zdefiniowaną metrykę można obliczać zarówno dla całości oprogramowania, jak i dla 
poszczególnych  komponentów.  Jednym  z  przykładów  zastosowania  jest  pomiar 
przyrostu  jakości  kolejnych,  poprawionych  wersji  programu  w  stosunku  do  wersji 
początkowej. 

Problemem  podczas  obliczania  tej  metryki  jest  brak  ogólnie  przyjętej  definicji 

„wiersza kodu programu". Można tę metrykę obliczać w stosunku do liczby instrukcji 
kodu wynikowego (np. w asemblerze) albo do liczby wierszy kodu źródłowego (np. w 
C,  C#  lub  w  Javie).  Przyjmując  za  podstawę  program  źródłowy,  można  liczyć 
wszystkie wiersze programu, wraz komentarzami i nagłówkami, albo tylko instrukcje 
wykonalne  i  deklaracje  danych.  Jeżeli  ta  sama  instrukcja  lub  deklaracja  jest 
rozmieszczona w kilku wierszach tekstu, to można ją liczyć jako jedną instrukcję lub 
deklarację,  albo  jako  kilka  wierszy  tekstu.  Wszystkie  te  wątpliwości  nie  obniżają 
jednak  wartości  metryki  jako  narzędzia  wytwórcy  oprogramowania.  Każda  firma 
informatyczna  może  określić  własny  sposób  liczenia  metryki  częstości  defektów  i 
używać jej do porównywania jakości wytworzonego przez siebie kodu. 

 
Procent defektów poprawionych 
Wartość  tej  metryki,  równa  stosunkowi  liczby  defektów  poprawionych  do  liczby 

defektów  wykrytych  podczas  testów,  pozwala  ocenić  postęp  prac  nad  usuwaniem 

background image

defektów programu. Wynikiem tej oceny może być decyzja o przejściu do kolejnego 
etapu testów albo próbnej eksploatacji oprogramowania. 

 
Szacowanie liczby wszystkich defektów 
Przydatność  metryk  opartych  na  zliczaniu  wykrytych  defektów  programu  jest 

ograniczona  z  powodu  braku  znajomości  liczby  defektów  znajdujących  się 
początkowo w programie. Czy z faktu wykrycia i usunięcia np. 500 defektów wynika, 
że  program  jest  już  godny  zaufania?  Trudno  powiedzieć  -  jeśli  program  zawierał 
początkowo 500 defektów, to na pewno tak, ale jeśli zawierał ich 1000, to raczej nie. 

Metoda  zasiewu  defektów  (fault  seeding)  jest  próbą  eksperymentalnego 

oszacowania  liczby  wszystkich  defektów  programu.  Eksperyment  polega  na 
wprowadzeniu  do  programu  pewnej  znanej  liczby  defektów  -  nazywanych  dalej 
defektami sztucznymi - i odnajdywaniu ich podczas testowania na równi z defektami 
prawdziwymi.  Jeśli  przyjąć,  że  oba  rodzaje  defektów  są  znajdowane  tak  samo 
skutecznie,  to  stosunek  liczby  wykrytych  defektów  sztucznych  (n

s

)  do  liczby 

wszystkich  defektów  sztucznych  (N

s

)  powinien  być  taki  sam  jak  stosunek  liczby 

wykrytych  defektów  prawdziwych  (n

p

)  do  liczby  wszystkich  defektów  prawdziwych 

(N

p

): 

n

/ N

s

 = n

/ N

p

 

Trzy z tych wartości: N

s

, n

s

, n

p

 są po pewnym czasie testowania znane. Na ich 

podstawie można obliczyć czwartą: 

N

p

 = N

s

* n

p

 / n

s

 

 
Wartość  N

p

  można  traktować  jako  oszacowanie  rzeczywistej  liczby  wszystkich 

defektów programu. Wiarygodność metody jest tym większa, im bardziej zbliżone do 
siebie  są  typy  defektów  prawdziwych  i  wprowadzonych  do  programu  defektów 
sztucznych. 

 
 
 
 
 

background image

4. Metody testowania 

Celem testowania jest doświadczalne porównanie wyników działania programu ze 

wzorcem, którym jest specyfikacja tego programu. Jeśli wyniki są zgodne, to program 
uznaje się za poprawny. Problem polega na tym, że ze względu na olbrzymią liczbę 
różnych  sposobów  działania  programu,  wyznaczoną  przez  liczbę  wszystkich 
możliwych kombinacji wartości danych wejściowych, nie da się sprawdzić działania 
programu we wszystkich sytuacjach w rozsądnym czasie. Tym, co jest możliwe, jest 
wybranie  do  testów  pewnego  reprezentatywnego  zbioru  wartości  danych  i 
sprawdzenie  działania  programu  dla  tej  ograniczonej  liczby  przypadków  testowych. 
Głównym  zadaniem  etapu  projektowania  testów  jest  wybór  takiego  zbioru  wartości 
danych,  który  umożliwi  dostatecznie  wiarygodne  sprawdzenie  programu  w  ramach 
posiadanego czasu i zasobów. 

Metodę  projektowania  testów  można  oprzeć  na  specyfikacji,  która  nie  określa 

wewnętrznej  budowy  programu.  Różne  przypadki  testowe  mogą  tu  reprezentować 
różne  sposoby  działania  opisane  w  specyfikacji  programu  (jak  różne  scenariusze, 
różne  reguły  biznesowe  itp.).  Albo  przeciwnie,  znając  budowę  programu,  można 
wykorzystać  tę  wiedzę,  aby  w  ograniczonej  liczbie  kroków  przetestować  wszystkie 
jego  elementy  składowe  i  ich  połączenia.  Różne  przypadki  testowe  mogą  tu 
reprezentować  różne  możliwe  drogi  przetwarzania  danych  wejściowych  w  wyniki. 
Zależnie  od  wybranego  podejścia  mówi  się  wtedy  o  testowaniu  czarnej  skrzynki,  o 
nieznanym wnętrzu, lub białej skrzynki, o znanej zawartości. Obydwa podejścia mają 
swoje zalety i wady i obydwa są stosowane. 

Metoda  białej  skrzynki  (white  box  testing)  umożliwia  dokładne  przetestowanie 

wszystkich składników oprogramowania oraz ułatwia znalezienie i usunięcie błędów. 
Oparcie budowy testów na budowie programu oznacza jednak oparcie się na czymś, 
co  być  może  jest  błędne.  To  z  kolei  może  uniemożliwić  odnalezienie  wszystkich 
defektów  -  np.  jeżeli  pewnych  funkcji  w  programie  nie  ma,  to  bazując  tylko  na 
strukturze programu, nie będzie można tego braku odnaleźć.  

Metoda  czarnej  skrzynki  (black  box  testing)  jest  natomiast  odpowiednia  do 

testowania  przez  użytkownika,  który  ani  nie  zna,  ani  nie  chce  znać  wewnętrznej 
struktury programu. Celem użytkownika jest upewnienie się, czy program wykonuje 
potrzebne mu funkcje i czy robi to wystarczająco dobrze. Znaczenie może mieć także 

background image

sprawdzenie,  jak  zachowuje  się  program  obsługiwany  niezgodnie  z  intencjami 
użytkownika. 

Niezależnie  od  metody  testowania,  wykorzystanej  na  danym  poziomie  testów, 

konieczne  jest  zawsze  przygotowanie  dostatecznie  dużej  liczby  danych  testowych, 
które posłużą do sprawdzenia poprawności działania programu. Analiza specyfikacji 
lub struktury programu, niezbędna do wytypowania właściwych wartości danych, jest 
działaniem  drogim,  zwłaszcza  na  poziomie  testów  jednostkowych,  w  których 
testowaniu mogą podlegać tysiące, a nawet dziesiątki tysięcy odrębnych funkcji lub 
klas  programu.  Dlatego  często  generuje  się  dane  w  sposób  losowy  i  ocenia 
efektywność  testowania  za  pomocą  metryk  i  metod  opisanych  w  podrozdziale  3. 
Dodatkową zaletą losowej generacji danych testowych jest statystyczna niezależność 
od siebie (brak korelacji) poszczególnych przypadków testowych. 

 
 

4.1 Testowanie czarnej skrzynki 

Testowanie  metodą  czarnej  skrzynki  jest  próbą  sprawdzenia  poprawności 
zachowania programu we wszystkich sytuacjach, jakie można wyróżnić na podstawie 
jego  specyfikacji.  Projektowanie  przypadków  testowych  polega  na  wybraniu  zbioru 
poprawnych i niepoprawnych wartości danych wejściowych zapewniających pokrycie 
całej  przestrzeni  zachowań  programu.  Ocenę  kompletności  testowania  można 
wyrazić  za  pomocą  metryk  pokrycia  wymagań,  opisanych  w  punkcie  3.2.  Metoda 
umożliwia  wykrycie  odstępstw  i  braków  implementacji,  ale  nie  gwarantuje 
wyczerpującego  sprawdzenia  wszystkich  wewnętrznych  elementów  programu. 
Metoda  jest  stosowana  przede  wszystkim  na  wyższych  poziomach  testowania,  na 
których występują programy o wielkiej złożoności wewnętrznej. 

Deterministyczne  projektowanie  przypadków  testowych  polega  na  poszukiwani 

jak  najmniejszego  zbioru  wartości  danych  wejściowych,  takiego  który  pozwoli 
zademonstrować  wszystkie  rodzaje  różnych  zachowań  programu.  W  tym  celu 
konieczne  jest  podzielenie  wszystkich  możliwych  wartości  danych  wejściowych  na 
klasy wartości przetwarzanych podobnie (w sensie jakiegoś kryterium) i wybranie do 
testów  pewnej  liczby  wartości  należących  do  każdej  z  tych  klas.  Do  najczęściej 
stosowanych metod deterministycznego projektowania testów należą: 

 

analiza klas równoważności  

background image

 

analiza wartości brzegowych.  

Wraz z rozwojem metod obiektowych pojawiły się te: metody odwołujące się do 

specyfikacji  przypadków  użycia.  Wymienione  metody  nie  są  ze  sobą  sprzeczne, 
dlatego w praktyce stosuje się często kombinację różnych metod. 

 
 
Analiza klas równoważności 
Analiza  klasy  równoważności  (equivalence  partitioning)  ma  na  celu  podział 

wszystkich  możliwych  wartości  danych  wejściowych  programu  na  klasy  (zbiory) 
przetwarzane  w  podobny  sposób.  Uzasadnieniem  metody  jest  założenie,  że  różne 
defekt)  programu  są  związane  z  różnymi  sposobami  przetwarzania.  Projektowanie 
testów  rozpoczyna  się  od  analizy  specyfikacji  testowanego  programu  i  podziału 
wszystkich  możliwych  wartości  danych  wejściowych  na  klasy  równoważności, 
zawierające wartości przetwarzane w taki sam sposób. W kolejnym kroku następuje 
wybranie pewnej liczby wartości danych testowych z każdej klasy. W całym procesie 
projektowania  przypadków  testowych  należy  uwzględnić  zarówno  klasy 
odpowiadające  poprawnym  wartościom  danych  wejściowych,  jak  i  klasy 
odpowiadające  wartościom  błędnym.  Liczba  przypadków  testowych  dobieranych  z 
różnych klas równoważności decyduje o wiarygodności testowania. 

 

 

Rysunek 9. Klasy równoważności wartości czasu 

 
Na  przykład,  projektując  testy  komponentu,  którego  dane  wejściowe  obejmują 

określenie  czasu,  można  zauważyć,  że  prawidłowe  wartości  liczby  godzin  leżą  w 
zakresie  0-23,  a  liczby  minut  -  w  zakresie  0-59.  Przyjmując  ten  podział,  można 
wyróżnić  dziewięć  klas  równoważności  (rys.  9).  Projekt  testów  powinien  objąć 
wartości danych wejściowych z każdej z tych dziewięciu klas równoważności. 

 
 

background image

Analiza wartości brzegowych 
Analiza wartości brzegowych (boundary value analysis) ma na celu znalezienie 

wszystkich osobliwości leżących w całym zakresie danych wejściowych, jakie mogą 
pojawić  się  na  wejściu  programu.  Uzasadnieniem  metody  jest  założenie,  że  błędy 
mogą być powodowane nieprzewidzianym zachowaniem programu w okolicy wartości 
granicznych. W związku z tym dla każdej znalezionej wartości granicznej przyjmuje 
się jako przypadki testowe trzy wartości danych: wartość graniczną leżącą wewnątrz 
obszaru wartości prawidłowych oraz wartość o jeden mniejszą i o jeden większą od 
wartości granicznej. 

Naturalnymi wartościami brzegowymi są granice klas równoważności. Stosując tę 

metodę,  trzeba  jednak  uwzględnić  także  granice  innego  rodzaju,  wynikające  z 
właściwości  użytych  w  programie  typów  danych.  Na  przykład,  jeżeli  temperatura  w 
oprogramowaniu sterującym klimatyzacją budynku jest przechowywana jako wartość 
zmiennopozycyjna (typu 

float lub real), to jako wartości brzegowe należy też przyjąć 

wartość  zero  oraz  wartości  leżące  na  obu  krańcach  zakresu.  Testowanie  wartości 
brzegowej  powinno  objąć  trzy  wartości  różniące  się  o  jeden  bit  w  maszynowej 
reprezentacji  liczby.  Warto  zauważyć,  że  w  tym  miejscu  wykracza  się  nieco  poza 
zakres  podejścia  czarnej  skrzynki  i  korzysta  z  pewnych  danych  na  temat  sposobu 
reprezentacji liczb w programie. 

 
Testowanie sposobów użycia 
Testowanie  sposobów  użycia  oprogramowania  (use  case  testing)  ma  na  celu 

znalezienie  i  przetestowanie  wszystkich  dostępnych  dla  użytkownika  sposobów 
wykorzystania  programu.  Uzasadnieniem  tej  metody  jest  założenie,  że  podobne 
wykorzystanie programu ujawnia podobne błędy. Szczegóły metody zależą od postaci 
specyfikacji  programu.  Jeżeli  ma  ona  postać  hierarchii  funkcji,  to  sposobem 
wykorzystania  programu  może  być  wykonanie  funkcji  lub  pewnej  sekwencji  funkcji 
tworzących  jakąś  biznesową  całość.  Jeżeli  specyfikacja  ma  postać  modelu 
przypadków  użycia,  to  sposobem  wykorzystania  jest  każdy  scenariusz  przypadku 
użycia.  Kolejne  przypadki  testowe,  projektowane  za  pomocą  tej  metody,  powinny 
więc  zawierać  takie  wartości  danych  wejściowych,  które  spowodują  wykonanie 
wszystkich funkcji lub wszystkich scenariuszy. 

background image

Metoda testowania sposobów użycia jest szczególnie często stosowana podczas 

projektowania  testów  akceptacyjnych  oprogramowania  wyspecyfikowanego  za 
pomocą metody przypadków użycia. Wiarygodność testowania będzie tym większa, 
im  większa  będzie  liczba  przypadków  testowych  sprawdzających  wykonanie 
poszczególnych scenariuszy. 

 
Testowanie losowe 
Losowa  metoda  projektowania  przypadków  testowych  (Monte  Carlo  method) 

opiera  się  na  założeniu,  że  przypadkowo  generowane  dane  testowe  rozłożą  się  w 
całym możliwym zakresie wartości danych wejściowych i po dostatecznie dużej liczbie 
prób pokryją cały zakres przetwarzania testowanego programu. Moment zakończenia 
testów  może  być  ustalony  na  podstawie  pomiaru  metryk  pokrycia  (klas 
równoważności  lub  metryk  opisanych  w  punkcie  3.2)  albo  -  jak  bywa  najczęściej  - 
może być określony arbitralnie w harmonogramie projektu. 

Środowisko  losowego  testowania  programu  składa  się  ze  standardowego 

generatora  liczb  losowych  (np.  funkcja  biblioteczna 

rand),  filtru  przetwarzającego 

liczby losowe na dane leżące w zakresie wejściowym testowanego programu oraz z 
automatu rejestrującego wynik (rys. 10). Zaletami losowej generacji danych testowych 
są  uproszczenie  etapu  projektowania  przypadków  testowych  oraz  łatwość 
automatyzacji.  Do  jej  wad  należy  zaliczyć  skomplikowany  proces  analizy 
zarejestrowanych wyników oraz brak gwarancji osiągnięcia zadowalającego pokrycia 
testów w założonym czasie. 

 

 

Rysunek 10. Środowisko losowej generacji danych testowych 

 
 

4.2. Testowanie białej skrzynki 

Testowanie metodą białej (szklanej) skrzynki jest próbą sprawdzenia poprawności 

wszystkich  elementów,  z  których  zbudowany  jest  program.  Projektowanie 
przypadków  testowych  polega  na  wybraniu  takiego  zbioru  wartości  danych 

background image

wejściowych,  który  zapewni  pełne  pokrycie  kodu  programu,  zgodnie  z  przyjętym 
kryterium  oceny  kompletności,  np.  z  wykorzystaniem  metryk  pokrycia  kodu, 
opisanych  w  punkcie  3.1.  Istotną  wadą  metody  jest  jej  zależność  od  wewnętrznej 
struktury  programu  -  każda  zmiana  tej  struktury  może  wymagać  modyfikacji  zbioru 
przypadków  testowych.  Metoda  może  być  stosowana  na  wszystkich  poziomach 
testowania  z  wyjątkiem  testowania  akceptacyjnego.  W  praktyce  jednak  głównym 
obszarem jej zastosowania jest testowanie jednostkowe. 

 
Testowanie ścieżek 
Testowanie ścieżek (path testing) ma na celu sprawdzenie poprawności działania 

wszystkich  instrukcji  wchodzących  w  skład  programu.  Uzasadnieniem  metody  jest 
założenie,  że  źródłem  błędów  są  defekty  tkwiące  w  instrukcjach  programu. 
Sprawdzenie wszystkich instrukcji powinno więc pozwolić na ujawnienie wszystkich 
defektów.  Kluczowe  znaczenie  przy  projektowaniu  przypadków  testowych  ma 
rozmieszczenie instrukcji warunkowych, które decydują o wyborze ścieżki obliczeń i 
wykonaniu leżących na tej ścieżce bloków instrukcji. Ocenę kompletności testowania 
umożliwiają  metryki  pokrycia  kodu.  Obliczenie  tych  metryk  podczas  trwania  testów 
wymaga  zarejestrowania  przejścia  wykonania  programu  przez  wszystkie  wyjścia 
instrukcji  warunkowych  (decyzji).  Można  w  tym  celu  wykorzystać  pułapki  programu 
uruchomieniowego (debugger). 

Przygotowanie  testów  wymaga  znalezienia  -  podczas  statycznej  analizy  kodu  - 

wszystkich  rozgałęzień  programu,  a  następnie  umieszczenia  w  punktach  wyjścia 
pułapek  powodujących  przekazanie  sterowania  do  programu  uruchomieniowego. 
Czynność  tę  nazywa  się  czasem  instrumentacją  testowanego  programu.  Tak 
przygotowany program może być wielokrotnie wykonywany w środowisku testowym z 
różnymi  wartościami  danych  wejściowych.  Każde  zadziałanie  pułapki  jest 
rejestrowane, po czym wykonanie programu jest wznawiane i przebiega dalej aż do 
osiągnięcia końca. 

Wartości danych testowych, dostarczane podczas kolejnych wywołań programu, 

mogą być wybierane przez testera, np. na podstawie analizy warunków rozgałęzień, 
albo  też  mogą  być  generowane  losowo.  Koniec  testowania  wyznacza  osiągnięcie 
pełnego pokrycia programu zgodnie z wybraną metryką - pokrycia bloków, decyzji lub 
dróg  programu.  Wyniki  zarejestrowane  dla  wszystkich  wykonanych  przypadków 

background image

testowych  są  porównywane  z  wartościami  obliczonymi  na  podstawie  specyfikacji 
programu. Jeśli wszystkie obliczone wyniki są zgodne z oczekiwaniami, to testowany 
program jest uznawany za poprawny. 

Poważnym  problemem  tej  metody  testowania  jest  duża  liczba  przypadków 

testowych,  wykonywanych  podczas  testów,  i  wynikający  z  tej  liczby  duży  rozmiar 
danych, które muszą być poddane analizie po zakończeniu testów. 

 
Testowanie mutacyjne 
Testowanie  mutacyjne  (mutation  testing)  ma  na  celu  identyfikację  skutecznych 

przypadków  testowych  oraz ograniczenie  rozmiaru  danych  rejestrowanych podczas 
testów i analizowanych po ich zakończeniu, przez odrzucenie wyników przypadków 
testowych  uznanych  za  nieskuteczne.  Rozróżnienie  skutecznych  i  nieskutecznych 
przypadków  testowych  następuje  na  podstawie  wyników  wykonania  tego  samego 
testu  dla  dwóch  wersji  programu  -  oryginalnej  i  zmutowanej  przez  celowe 
wprowadzenie  pewnej  liczby  defektów.  Uzasadnieniem  metody  jest  założenie,  że 
defekty  naturalne  są  wykrywane  równie  skutecznie  jak  defekty  wprowadzone 
sztucznie. Przypadek testowy, który wykrywa błąd sztuczny - tzn. taki, którego wynik 
jest inny w programie oryginalnym niż w zmutowanym - jest uznawany za skuteczny. 
Przypadek  testowy,  który  nie  wykrywa  błędu  i  nie  potrafi  odróżnić  mutanta,  jest 
uznawany za nieskuteczny.  

Przygotowanie  testów  mutacyjnych  nie  wymaga  statycznej  analizy  programu. 

Mutacje mogą być generowane losowo (np. przez losową zmianę znaków w tekście 
programu), z ograniczeniem do zmian zgodnych ze składnią języka programowania. 
Dla zwiększenia skuteczności metody zwykle generuje się dużą liczbę zmutowanych 
wersji  programu  (mutantów).  Wszystkie  mutanty  są  kompilowane  i  wykonywane 
równolegle  z  oryginalnym  programem  na  tych  samych  danych  testowych.  Wyniki 
uzyskane  przez  testowany  program  są  porównywane  z  wynikami  mutantów.  Jeżeli 
wszystkie wyniki są takie same, to przypadek testowy zostaje uznany za nieskuteczny 
i jego wyniki są ignorowane. Jeśli wynik testowanego programu różni się od wyniku 
choćby jednego mutanta, to przypadek testowy zostaje uznany za skuteczny, a wynik 
obliczony przez testowany program jest rejestrowany do późniejszej analizy. Wyniki 
uzyskane  w  wyniku  wykonania  mutantów  nie  mają  znaczenia  i  nie  podlegają 

background image

rejestracji.  Schemat  blokowy  ilustrujący  zasadę  testowania  mutacyjnego  jest 
pokazany na rys. 11. 

 

 

Rysunek 11. Środowisko do testowania mutacyjnego 

 
Zaletą  testowania  mutacyjnego  jest  łatwość  automatyzacji  testów.  Wadą  jest 

ograniczenie mutacji sterujących wyborem rejestrowanych przypadków testowych do 
takich  defektów,  które  mogą  być  wynikiem  drobnych  pomyłek  programisty.  W  ten 
sposób  zbiór  danych  testowych  zostaje  niejawnie  skorelowany  z  postacią 
testowanego programu, który może zawierać też błędy grube. Do wad metody można 
także  zaliczyć  konieczność  posiadania  automatycznych  narzędzi  wspomagających 
oraz  bardzo  wydajnego  środowiska  testowego,  które  musi  być  zdolne  do 
równoległego wykonania programu i wszystkich jego mutantów. 

 
 
 

5. Automatyzacja testowania 

Podczas  testowania,  np.  nowej  jednostki  programu,  ten  sam  scenariusz 

przypadku  testowego  jest  wykonywany  wielokrotnie  dla  różnych  wartości  danych 
testowych.  Jeżeli  przetestowana  jednostka  jest  wielokrotnie  modyfikowana,  np.  w 
kolejnych  iteracjach  procesu  wytwórczego,  to  te  same  testy  są  wykonywane 
wielokrotnie  w  ramach  testów  regresji.  Testowanie  jest  czynnością  powtarzalną,  a 
jednocześnie  pracochłonną.  Powtarzalność  wskazuje,  że  automatyzacja  testowania 
jest możliwa. Pracochłonność sugeruje, że automatyzacja może przynieść wymierne 
korzyści  ekonomiczne.  Dlatego  zainteresowanie  przemysłu  informatycznego 
rozwojem narzędzi wspomagających testowanie stale wzrasta. 

background image

Ponieważ  testowanie  jest  procesem  złożonym,  można  rozważać  narzędzia 

wspomagające różne etapy tego procesu: projektowanie testów, wykonanie i analizę 
wyników.  Innego  wspomagania  wymaga  testowanie  jednostek  programu  metodą 
białej skrzynki, innego testowanie aplikacji na poziomie funkcji interfejsu użytkownika, 
a jeszcze innego testowanie wydajności oprogramowania. Dlatego trudno jest podać 
spójną klasyfikację narzędzi wspomagających testowanie. Na rynku istnieje ich wiele, 
poczynając  od  komercyjnych  systemów  łączących  narzędzia  różnego  rodzaju,  a 
kończąc na darmowych narzędziach dedykowanych do określonych zadań. 

 
Narzędzia elementarne - sterowniki i namiastki 
Elementarnym  warunkiem  wykonania  testu  jest  możliwość  uruchomienia  i 

wykonania  testowanego  programu.  Jeżeli  przedmiotem  testowania  jest  jakiś 
niesamodzielny moduł programu, np. klasa Rewers z punktu 4.4, zawierająca metodę 
wypozycz( ): 

 
public int wypozyczCWolumin wolumin)  

if ( pozycja != wolumin.pozycja ) return ERROR;  
this.wolumin = wolumin; 
okresWypozyczenia = pozycja.obliczOkres(czytelnik.status); 
return OK; 


 
to wywołanie tej metody z właściwym argumentem wymaga napisania programu 

głównego,  który  tę  metodę  wywoła.  Taki  program  główny  -  napisany  specjalnie  na 
potrzeby testowania - jest nazywany sterownikiem testowym (test driver). Ponieważ 
testowana metoda 

wypożycz() wywołuje podczas wykonania metodę obliczOkres( ) z 

innej klasy, która być może nie została jeszcze opracowana lub która jest testowana 
równolegle przez kogoś innego, to wykonanie testowanej metody wymaga dołączenia 
do  niej  jakiejś  funkcji,  która  zastąpi  brakującą  metodę.  Taki  program  symulujący 
podczas testów zachowanie brakującego komponentu jest nazywany namiastką (test 
stub). 

Sterowniki  i  namiastki  są  niezbędne  w  każdym  procesie  testowym,  również 

przeprowadzanym ręcznie. Dlatego nie są one uważane za narzędzia automatyzacji 
testowania.  Z  drugiej  strony  zarówno  sterownik  testowy,  jak  i  namiastka  mogą  być 

background image

bardzo  proste  albo  bardzo  złożone.  Prosty  sterownik  może  odczytać  argument  z 
klawiatury, wywołać testowaną funkcję i wyświetlić wynik. Złożony sterownik testowy 
może  wielokrotnie  wywoływać  wykonanie  testowanego  programu  z  różnymi 
argumentami,  zapisanymi  na  liście  lub  pobieranymi  z  pliku,  i  rejestrować  wyniki  w 
innym pliku. Prosta namiastka może być funkcją niemal pustą, zwracającą ustaloną 
wartość.  Złożona  namiastka  może  symulować  funkcjonalność  brakującego 
komponentu albo zwracać różne wartości, generowane losowo lub pobierane z pliku. 
Zestaw złożony z takiego rozbudowanego sterownika, niezbędnych namiastek oraz 
pliku danych testowych może być używany wielokrotnie, np. podczas testów regresji, 
automatycznie  realizując  testy  i  generując  za  każdym  razem  kompletny  plik  z 
zarejestrowanym wynikiem. 

 
Automatyzacja testów jednostkowych 
Testowanie  jednostek  programu  jest  procesem  masowym  -  dotyczy  wszystkich 

opracowanych klas programu - i wielokrotnie powtarzanym podczas testów regresji. 
Dlatego  ten  obszar  testów  stal  się  polem  intensywnego  rozwoju  narzędzi 
automatycznego  testowania.  Wzorcem,  który  wyznaczył  kierunek  rozwoju 
automatyzacji testów jednostkowych, stała się darmowa biblioteka JUnit, opracowana 
do  testowania  programów  napisanych  w  języku  Java.  Sukces  tej  biblioteki 
doprowadził  do  powstania  podobnych  narzędzi  wspomagających  tworzenie  testów 
programów w innych językach, takich jak CPPUnit dla języka C++, DUnit dla Delphi 
(obiektowa  wersja  języka  Pascal),  NUnit  dla  C#  lub  PHPUnit  i  PerlUnit  dla 
popularnych języków skryptowych. 

W  celu  zilustrowania  sposobu  użycia  biblioteki  JUnit  rozważmy  proces 

przygotowania testu metody obliczOkres( ) klasy Ograniczona z punktu 4.4: 

 

public class Ograniczona extends Pozycja  

public int obliczOkres(int status) 

//reguła RB2 

switch ( status ) { 

case PRACOWNIK: return 30;  
case DOKTORANT: return 7;  
default: return 0; 

background image

 
Przeprowadzenie testu wymaga utworzenia obiektu testowanej klasy, wywołania 

metody i porównania wyniku z oczekiwaniami. Wszystkie te czynności należy zawrzeć 
w klasie testu, która na mocy umowy - ale tylko umowy - nosi zazwyczaj nazwę równą 
nazwie testowanej klasy z przyrostkiem Test: 

 

import org.junit.* ; 
import static org.junit.Assert.* ; 
 
public class OgraniczonaTest {  
@Test 
public void test_oblicz0kres() { 

Pozycja p = new Ograniczona(...) ; 
assertTrue(p.oblicz0kres(PRACOWNIK)== 30); 
assertTrue(p.oblicz0kres(DOKTORANT)== 7); 
assertTrue(p.oblicz0kres(STUDENT) == 0); 


 
Zasadniczym elementem utworzonej klasy jest metoda pełniąca rolę testu - w tym 

przykładzie  jest  to  metoda 

test_obliczOkres(  )  -  wyróżniona  za  pomocą  adnotacji 

@Test.  Obecność  tej  adnotacji  umożliwi  automatyczne  odszukanie  i  wywołanie 
metody przez  sterownik  testowy. Poza  metodami  testowymi  utworzona  klasa  może 
zawierać dowolne inne metody pomocnicze. Inne adnotacje pozwalają na wskazanie 
metod, które powinny być wywołane przed lub po wywołaniu metody testowej. 

Pierwszym elementem metody testu jest utworzenie obiektu klasy 

Ograniczona, 

którego  zachowanie  będzie  przedmiotem  weryfikacji.  Następnie  wywoływana  jest 
metoda 

assertTrue(  ),  wchodząca  w  skład  biblioteki  JUnit,  która  sprawdza,  czy 

podane  jako  argument  wyrażenie  jest  prawdziwe.  Istnieje  kilka  metod  assert... 
różniących się postacią sprawdzanego warunku. 

Przygotowane  klasy  testowe  mogą  być  dołączone  do  testowanego  programu, 

skompilowane  i  wykonane  za  pomocą  dołączonego  do  biblioteki  sterownika  (JUnit 
test runner) na konsoli  tekstowej lub za pomocą licznych środowisk graficznych. W 
każdym  przypadku  wynikiem  wykonania  metody  assert...  może  być  komunikat 
informujący o ewentualnym błędzie. 

Biblioteka JUnit jest bardzo rozbudowana. Zawiera m.in. mechanizmy grupowania 

testów  w  zestawy,  sprawdzania  wyjątków,  specyfikowania  wspólnych  czynności 

background image

przygotowawczych  i  zamykających  oraz  współpracy  ze  zbiorami  danych.  Pełne 
przedstawienie możliwości tego narzędzia przekracza ramy. 

 
Narzędzia pokrycia kodu 
Ręczne  obliczanie  metryk  pokrycia  kodu  (punkt  3.1)  podczas  testów  jest 

uciążliwe. Dlatego istnieje cały szereg narzędzi pokrycia kodu (code coverage tools), 
zarówno  komercyjnych,  jak  i  darmowych,  służących  automatyzacji  tego  zadania. 
Działanie takich narzędzi obejmuje zwykle trzy kroki. 

1.  Statyczną analizę kodu programu i zaznaczenie wszystkich rozgałęzień. 
2.  Instrumentację  kodu,  polegającą  na  dołączeniu  funkcji  rejestrujących 

przejście wykonania programu przez każde rozgałęzienie. 

3.  Rejestrację  śladu  wykonania  programu  (podczas  testów)  i  obliczenie 

wartości metryk. 

Niektóre narzędzia współpracują bezpośrednio z biblioteką JUnit (lub jej wersjami 

dla  innych  języków  programowania)  i  umożliwiają  ocenę  pokrycia  kodu  przez 
konkretny zestaw testów. 

 
Odtwarzanie działań użytkownika 
Testowanie  funkcji  oprogramowania  metodą  czarnej  skrzynki  polega  na 

wielokrotnym  wykonaniu  testowanego  komponentu  dla  różnych  danych  testowych 
wprowadzanych  za  pośrednictwem  jego  interfejsu.  W  przypadku  testowania 
kompletnej  aplikacji  jest  to  interfejs  użytkownika.  Jeżeli  program  ma  interfejs 
tekstowy,  to  wykonanie  testów  łatwo  zautomatyzować  za  pomocą  sterownika 
testowego,  który  przekieruje  wejściowy  strumień  programu  z  klawiatury  do  pliku 
danych testowych, a strumień wyjściowy z ekranu do pliku wyników. Jeżeli testowana 
aplikacja ma interfejs graficzny, to automatyzacja testów wymaga innego podejścia. 

Narzędziem  automatyzacji  testów  aplikacji  wyposażonej  w  graficzny  interfejs 

użytkownika  jest  zmodyfikowana  biblioteka  operacji  okienkowych,  która  po 
rekompilacji i uruchomieniu programu przechwytuje i zapamiętuje działania operatora, 
takie jak kliknięcia przycisków, ruchy myszką i wypełnienie pól tekstowych. Pierwszy 
przebieg testów jest obsługiwany interaktywnie przez człowieka, którego ruchy oraz 
wyniki  działań  są  zapamiętywane  w  pliku.  Po  zakończeniu  wykonania  możliwe  jest 

background image

automatyczne,  wielokrotne  odtwarzanie  wszystkich  zapamiętanych  działań, 
połączone z porównaniem zgodności wyników. 

Zastosowanie  narzędzia  odtwarzającego  działania  użytkownika  (record  and 

playback  feature)  może  przynieść  wymierne  korzyści  w  postaci  automatycznego 
wykonywania  testów  oprogramowania  rozwijanego  w  sposób  iteracyjny  lub 
oprogramowania po modyfikacji. W tym ostatnim przypadku wadą metody jest jednak 
wrażliwość na wszelkie zmiany dokonywane w interfejsie użytkownika. 

Technika  odtwarzania  działań  użytkownika,  połączona  z  zupełnie  innym 

mechanizmem  realizacyjnym,  umożliwia  też  automatyzację  testowania  aplikacji 
internetowych.  W  tym  przypadku  jednak  przedmiotem  przechwytywania  i 
porównywania nie są działania użytkownika, tylko wymieniane z użytkownikiem strony 
html. Zaletą metody jest brak konieczności ingerowania w kod aplikacji. 

 
Testowanie wydajności 
Testowanie  wydajności  oprogramowania  działającego  w  trybie  wsadowym,  np. 

oprogramowania  naliczającego  dopłaty  rolne  na  podstawie  wcześniej 
wprowadzonych wniosków, nie wymaga stosowania automatycznych narzędzi innych 
od  generatora  zawartości  testowej  bazy  danych.  Problem  pojawia  się  podczas 
testowania  systemów  interaktywnych,  np.  oprogramowania  systemu  bankowego, 
które powinny obsługiwać wielu (tysiące) użytkowników jednocześnie. Wykorzystanie 
kilku  tysięcy  testerów,  jakkolwiek  teoretycznie  możliwe,  byłoby  drogie  i 
nieprzewidywalne  -  raz  zarejestrowanego  wyniku  nie  dałoby  się  powtórzyć  po  raz 
drugi dokładnie w ten sam sposób. 

Rozwiązaniem  problemu  jest  użycie  tzw.  robota  testowego  (test  robot),  czyli 

oprogramowania  symulującego  działanie  dużej  liczby  użytkowników.  Aby  obniżyć 
koszty,  robot  nie  wykorzystuje  zwykle  graficznego  interfejsu  użytkownika,  lecz 
przesyła  dane  wejściowe,  np.  polecenia  przelewu  z  konta  na  konto  w  systemie 
bankowym,  poprzez  interfejs  najłatwiej  dostępny.  Na  przykład,  jeżeli  testowane 
oprogramowanie  działa  na  serwerze  komunikującym  się  ze  stacjami  roboczymi 
użytkowników  poprzez  sieć,  za  pomocą  protokołu  HTTPS,  to  robot  generuje 
obciążenie w postaci sekwencji pakietów tego protokołu. Jeżeli natomiast testowaniu 
podlega komponent EJB komunikujący się z otoczeniem poprzez kolejki JMS (Java 
Message Service), to robot generuje serie komunikatów JMS. 

background image

Robot  generujący  obciążenie  dla  konkretnej  aplikacji  i  konkretnego  protokołu 

komunikacyjnego  jest  narzędziem  prostym.  Drugą  częścią  problemu  jest  jednak 
ocena  wyników  testowania.  Niekiedy  wystarczy  rejestrowanie  strumieni  danych 
wejściowych  i  wyjściowych,  za  pomocą  standardowych  narzędzi  administratora 
systemu.  W  takim  przypadku  ocena  wyników  wymaga  późniejszej  analizy  treści 
dziennika.  Czasami  wystarczy  sam  pomiar obciążenia  systemu  - użycia  procesora, 
zajętości pamięci - obserwowany za pomocą narzędzi administratora w czasie trwania 
testu.  Bardziej  zaawansowanym  sposobem  jest  automatyczna  analiza  wyników 
przetwarzania przez odpowiednio zaprogramowanego robota, który może np. mierzyć 
czas odpowiedzi na wysiane do testowanej aplikacji żądanie (rys. 12). 

 

 

 

Rysunek 12. Robot testowy 

 
Jeszcze  inny  sposób  prowadzenia  testów  umożliwia  połączenie  testów 

wydajnościowych  z  testami  funkcjonalnymi.  W  tym  podejściu  robot  wytwarza 
obciążenie,  którego  poziom  jest  kontrolowany  za  pomocą  narzędzi  administratora. 
Wyniki przetwarzania danych dostarczanych przez robota nie są rejestrowane. Na tle 
tego  obciążenia  wykonuje  się  ręcznie  testy  funkcjonalne,  których  wyniki  weryfikują 
poprawność  działania  oprogramowania  przy  ustalonym  obciążeniu  systemu.  Takie 
podejście jest często stosowane podczas testowania akceptacyjnego. 

 
 
 
 
 

background image

6. Uwagi bibliograficzne 

Przegląd  dziedziny  testowania  programów  komputerowych  można  znaleźć  w 

książkach [90, 92]. Szersze ujęcie problemu, obejmujące także testowanie układów i 
zespołów cyfrowych systemu komputerowego, jest podane w [91]. 

Historia.  Testowanie  jest  nieodłącznym  elementem  tworzenia  programów. 

Systematyczne  podejście  do  badania  kompletności  testowania  za  pomocą  metryk 
pokrycia datuje się od pracy [99]. Główne ograniczenie testowania, którym jest brak 
możliwości  udowodnienia  poprawności  programu,  wyartykułowane  w  informatyce 
przez  Dijkstrę  [217],  wynika  wprost  z  ograniczeń  testowania  sformułowanych  przez 
Poppera  [258]  w  kontekście  falsyfikowania  teorii  naukowych.  Inspekcje  kodu  (por. 
punkt 7.3.2) są związane z nazwiskiem Fagana [97, 98]. Zgrabne i wciąż cytowane 
zdanie,  definiujące  czynności  weryfikacji  i  zatwierdzania  (walidacji):  „Vérification  is 
building  the  product  right,  and  Validation  is  building  the  right  producf\  pochodzi  od 
Boehma [96]. 

Metryki. Obszerny przegląd różnych metryk oraz modeli efektywności usuwania 

defektów oprogramowania można znaleźć w [114]. 

Biblioteka  JUnit.  Testowanie  jednostkowe  programów  napisanych  w  Javie  za 

pomocą  biblioteki  JUnit  staje  się  powoli  standardem.  Podręcznik  i  darmową  wersję 
biblioteki  można  znaleźć  w  Internecie  [253].  Dobrymi  podręcznikami  w  tradycyjnej 
formie są [89, 93]. Biblioteka JUnit wchodzi również w skład darmowego środowiska 
Eclipse [250]. 

Systemy równoległe. W książce są pominięte zupełnie zaawansowane problemy 

testowania systemów równoległych. Nie ma wielu książek podejmujących ten temat. 
Zainteresowany czytelnik może sięgnąć do dwóch całkiem nowych pozycji [94, 95].