====== Testowanie oprogramowania ======

W celu osiągnięcia wysokiej jakości produktu należy dokonywać eksperymentów z poszczególnymi jego komponentami (albo całym produktem) wykorzystując specjalne dobrane dane testowe i porównując wyniki uzyskane z wynikami przewidywanymi. Działalność ta jest określona mianem testowania i dotyczy operacyjnych cech programu, tzn. własności programu ujawniających się podczas jego działania. 
Ponieważ testowanie wymaga eksperymentowania z działającym kodem programu określane jest mianem analizy dynamicznej. W uzupełnieniu wymagana jest również analiza statyczna zmierzająca do pozyskania odpowiedniej informacji o funkcjonalności i strukturze badanego produktu, umożliwiającej projektowanie odpowiednich testów.

**Testowanie ma dwa cele:**
  * wykrycie i usunięcie błędów w systemie,
  * ocenę niezawodności systemu. 
 
**Testy można klasyfikować:**
  * Testy wykrywania błędów. Celem jest wykrycie jak największej liczby błędów w programie.
  * Testy statystyczne.      Celem jest wykrycie przyczyn najczęstszych błędnych wykonań oraz ocena niezawodności systemu.

**Inna klasyfikacja obejmuje podział na:**
  * Testy dynamiczne. Wykonanie programu, porównanie wyników.
  * Testy statyczne. Analiza kodu.

**Kolejna klasyfikacja wprowadza:**
  * Testy modułów.
  * Testy systemów.
  * Testy akceptacji.

Analiza statyczna obejmuje różne reprezentacje programu – począwszy od abstrakcyjnej wizji przedstawionej w specyfikacji wymagań poprzez specyfikację projektową aż po szczegółową i bardzo techniczną reprezentację w postaci kodu źródłowego. 
Proces wytwarzania oprogramowania wymaga ciągłego nadzoru i oceny w celu wczesnego wykrywania anomalii, błędów i innych niepożądanych tendencji zanim wpłyną one niekorzystnie na działanie programu. Jest to problem **weryfikacji** rozumianej jako proces oceny produktu (lub jego składników) w celu stwierdzenia, czy spełnia on na zakończenie rozważanej fazy rozwojowej, założenia przyjęte na jej początku. Weryfikacja opiera się w dużej mierze na testowaniu, ale różni się od testowania tym, że dotyczy szerszego zakresu zagadnień, koncentrując się na sprawdzaniu poprawności różnych decyzji i złożeń na długo przed powstaniem wykonywanego kodu programu. 

Gdy weryfikacja dotyczy końcowego produktu i bada, czy spełnia on wymagania postawione mu na początku procesu wytwarzania, mamy do czynienia z procesem **walidacji** (atestowania). Walidacja zajmuje się oceną, czy powstaje taki produkt, o jaki chodzi jego przyszłym użytkownikom i czy zawarte w specyfikacji wymagania są wyrazem oczekiwań względem systemu. Walidacja prowadzona jest w docelowym środowisku programu.

Testowanie, weryfikacja i walidacja dotyczą różnych kategorii decyzyjnych. Są to pojęcia rozłączne w sensie ich celów szczegółowych, gdyż każde z nich zajmuje się odrębnym i specyficznie rozumianym aspektem jakości. Testowanie koncentruje się na jakości kodu, weryfikacja na jakości poszczególnych faz procesu wytwarzania w powiązaniu z ich produktami cząstkowymi, zaś walidacja na jakości produktu końcowego widzianej z perspektywy odbiorcy. Celem wspólnym jest zapewnienie odpowiednio wysokiej jakości wytwarzanego produktu. Testowanie, weryfikacja i walidacja – to kombinacja wzajemnie wspierających się procesów, rozciągających się na cały cykl wytwarzania oprogramowania.

__Procesy budowy poziomu zaufania w cyklu wytwarzania.__

{{:1.jpg|:1.jpg}}

Moduły testuje się oddzielnie, a następnie scala ze sobą i ponownie testuje jako całość.
W każdym kroku produkt danej fazy jest weryfikowany pod kątem produktu fazy poprzedzającej i tak aż do poziomu kodu źródłowego. 
Drugą grupę środków budowy zaufania do produktu stanowią eksperymenty z kodem w celu weryfikacji integrowanych jednostek (modułów). Eksperymenty przeprowadzane są w środowisku testowym lub docelowym. Właściwe przygotowanie eksperymentów wymaga projektowania testów, co polega na doborze właściwych danych testowych, zdefiniowaniu odpowiednich scenariuszy wykonania testu i sformułowania kryteriów zatrzymania testu. Projekt testu czerpie informacje z wielu źródeł: 
  * Projekt szczegółowy		– dla testowania jednostkowego, 
  * Projekt architektury	– testowanie integracyjne, 
  * Specyfikacja systemu	– testowanie systemowe, 
  * Wymagania użytkowe	        – testowanie akceptacyjne. 

Każde zdarzenie zainicjowane przez człowieka lub środowisko programu w wyniku, którego kod produkuje nieoczekiwany rezultat, nazywamy **błędem**. Błąd ujawnia się poprzez **awarię** programu, a powstaje w wyniku **defektu** w działaniu człowieka. Awaria polega na tym, że program nie jest zdolny wykonać prawidłowo, co najmniej jednej ze swoich funkcji w określonych warunkach operacyjnych. Błędne wykonanie – Nieprawidłowe działanie systemu w trakcie jego pracy.

**Ogólna klasyfikacja błędów w programach:**
  * Funkcjonalny. Zła lub brakująca funkcja.
  * Systemowy. Nieprawidłowe zarządzanie zasobami, błędne sterowanie.
  * Przetwarzania. Niewłaściwie przetwarzane dane w modułach.
  * Danych. Błędna specyfikacja, projekt, rozmieszczenie lub inicjalizacja struktur danych.
  * Kodowania. Niewłaściwe użycie języka programowania.
  * Dokumentacyjny. Niepełna lub błędna treść dokumentu.
  * Inny. Przyczyny nieznane.

**Techniki weryfikacji:**
  * Inspekcje – Techniki analizy wzrokowej produktu w poszczególnych fazach cyklu.
  * Interpretacje – Techniki zastąpienie instrukcji programu operacjami symbolicznymi.
  * Symulacje – Techniki imitowania akcji w modułach systemu.
  * Formalne dowody poprawności – Techniki wykazywania, że wskazany warunek dotyczący działania programu jest zawsze prawdziwy.
  * Testowanie funkcjonalne – Techniki eksperymentowania z kodem programu traktowanym jak „czarna skrzynka” w celu sprawdzenia czy dany moduł, grupa modułów lub cały program posiada przypisane mu cechy.
  * Testowanie strukturalne – Techniki eksperymentowania z kodem traktowanym jak „przeźroczysta skrzynka” w celu sprawdzenia czy moduł, grupa modułów lub cały program wykonują zaplanowane działania.
  * Testowane regresywne – Powtórzenie uprzednio przeprowadzonych testów po dokonaniu w programie zmian w celu potwierdzenia faktu całkowitego usunięcia błędu.
  * Pomiary osiągów – Techniki eksperymentowania w celu pomiaru konkretnych parametrów fizycznych związanych z wykonaniem programu.

Istotną częścią specyfikacji są kryteria akceptacji, określające wszystkie funkcjonalne i poza funkcjonalne własności produktu, jakie trzeba będzie później zademonstrować za pomocą testów akceptacyjnych. 

**Testowanie kodu.**
Testowanie wykorzystuje zarówno analizę statyczną, jaki i dynamiczną i składa się z szeregu czynności, takich jak: planowanie, projektowanie, wykonanie, ocena i dokumentowanie testów. Znacząco przyczynia się do zapewnienia wysokiej jakości produktu finalnego. 
Symboliczna interpretacja kodu źródłowego obejmuje interpretację tekstu programu, mającą na celu analizę przepływu sterowania i danych w tym programie, badania zależności między jego komponentami z zastosowaniem analizy regresywnej oraz wyznaczanie charakterystyk czasowo-pamięciowych. Analiza regresywna jest stosowana, gdy dokonano znaczącej modyfikacji w tworzonym kodzie. 

**Testowanie wykonywalnego kodu programu.**
Często używane pojęcia to dane testowe, przypadek testowy i kryterium zakończenia testu. Dla metod realizowanych na zasadzie „czarnej skrzynki” przypadki testowe są opisywane parami <wejście, wyjście>, a przy zastosowaniu „przeźroczystej skrzynki” koncentrujemy się na testowaniu elementów struktury programu np. pojedynczej instrukcji. Kryterium zakończenia testu umożliwia podjęcie decyzji, czy wykonano już wystarczającą liczbę eksperymentów. Wyróżniamy podejście: ilościowe (ma charakter statyczny, wykorzystuje duże zbiory przypadkowo wybranych danych wejściowych), jakościowe (koncentrują się na wykrywaniu konkretnych błędów). Każda strategia testowania używa swojego własnego modelu testowania i wynikające z tego modelu klasy błędów.

Najniższy poziom eksperymentowania z wykonywalnym kodem nazywa się **testowaniem jednostkowym**, które polega na wykonywaniu pojedynczych funkcji lub fragmentów kodu w oderwaniu od reszty systemu. Powyżej tego poziomu realizowane jest **testowanie integracyjne**, gdzie przetestowane jednostki kodu są stopniowo łączone w większą całość, a następnie ponownie testowane już jako grupa jednostek. Proces ten powtarzany jest aż do powstania całego systemu. Eksperymenty są wówczas prowadzone w docelowym środowisku programu. Ten najwyższy poziom nazywany jest **testowaniem systemowym**. Dodatkowo wyróżnia się poziom **testowania akceptacyjnego** stosowany bezpośrednio przed przeniesieniem prawa własności do produktu z wytwórcy na klienta.

**Testowanie systemowe** pozwala stwierdzić, czy wszystkie składniki systemu współpracują, tworząc system odpowiadający podanej specyfikacji. System traktujemy jako całość a testowaniu podlega jego funkcjonalność z punktu widzenia interakcji z użytkownikiem i środowiskiem. Lista zalecanych testów systemowych obejmuje m.in. testy: użyteczności, obsługi, pamięci, konfiguracji, instalacji, niezawodności, czy dokumentacji. W testach systemu wyróżniamy dwie główne techniki:
  * Testowanie wstępujące (testowanie od najmniejszych modułów aż do poziomu systemowego).
  * Testowanie zstępujące (rozpoczyna się od testowania modułów wyższego poziomu).

Testowanie akceptacyjne to jedyny przypadek, w którym zamiast szukać błędów demonstrujemy, że program działa. Lista czynności do wykonania w całości określana jest przez wymagania użytkowe – kryteria akceptacyjne. Wyróżnia się akceptację fazową (częściowa realizacja wymagań) oraz ostateczną (wypełnienie zobowiązań wynikających z kontraktu).

**Certyfikacja testu** to formalny akt pozwalający stwierdzić, że zainstalowany produkt jest identyczny względem produktu zademonstrowanego poprzednio w testowaniu akceptacyjnym.

**Techniki analizy statycznej** obejmują analizę treści i struktury dokumentów (w tym również kodu programu). W tym celu stosowane są recenzje, przeglądy, inspekcje i audyty, ale także inne techniki, takie jak: dowody poprawności, interpretacje symboliczne oraz statyczna analiza współbieżności.

**Techniki analizy dynamicznej**. Strategia testowania to metoda doboru przypadków testowych pod kątem określonego kryterium. W analizie dynamicznej mamy do czynienia z dwoma metodami strategii testowania: **czarna skrzynka** (traktuje program jako zbiór funkcji bez wnikania w sposób ich realizacji – strategie funkcjonalne), **przezroczysta skrzynka** (wykorzystują wiedzę o wewnętrznej strukturze testowanego programu; każdy przypadek testowy wymaga dobrania odpowiednich danych wejściowych lub ustawienia pewnych warunków – strategie strukturalne). 
Techniki funkcjonalne i strukturalne wprowadzają własne modele oraz charakteryzują błędy, jakie mogą wykrywać. Techniki funkcjonalne są potencjalnie zdolne do wykrycia wszystkich błędów, ale mogą do tego potrzebować nieskończonego zbioru przypadków testowych. Techniki strukturalne ograniczają się zaś tylko do pewnej klasy błędów, stąd w strategiach strukturalnych zbiór przypadków testowych jest zawsze skończony i w czasie eksperymentu możemy testować stopień zaawansowania testów. U podstaw testów funkcjonalnych leży obserwacja, że dane wejściowe można podzielić na pewne klasy, dla których system będzie działał podobnie.

**Przykład strategii funkcjonalnej** –> metoda Monte–Carlo.
Losowy wybór danych testowych z zastosowaniem rozkładu równomiernego. Nadaje się do testowania programu o wielkiej liczbie możliwych danych wejściowych. O zakończeniu testu decyduje człowiek.

**Przykład strategii strukturalnej** – Testowanie rozgałęzień i ścieżek.
Przedmiotem analizy jest ścieżka przechodząca przez program i tworząca ciąg instrukcji wykonywanych kolejno. Najprostsze kryterium zakończenia testu zakłada wykonanie każdego rozgałęzienia w programie przynajmniej raz.

**Testy statystyczne przebiegają według schematu:**
  * Losowa konstrukcja danych wejściowych zgodnie z rozkładem prawdopodobieństwa tych danych.
  * Określenie wyników poprawnego działania systemu dla tych danych.
  * Uruchomienie systemu, porównanie wyników.
Założeniem testów statystycznych jest przetestowanie działania systemu w typowych sytuacjach. Główną zaletą jest łatwość automatyzacji.

Czynności dotyczące weryfikacji, walidacji i testowania powinny zostać zaplanowane i udokumentowane w specjalnym dokumencie zwanym **Planem Weryfikacji i Walidacji Oprogramowania - planem WW**.

Żadna ze znanych technik testowania nie jest w stanie samodzielnie gwarantować wykrycia wszystkich błędów w programie. Typowe podejście wykorzystuje kilka uzupełniających się strategii. 
