Wyszukiwanie błędów Testowanie programów w celu wyszukania błędów
Zawartość Testowanie defektów Testowanie integracyjne Testowanie obiektowe Warsztaty do testowania
Proces testowania Testowanie komponentów Testy integracyjne Testowanie pojedynczych składowych programu Zazwyczaj odpowiedzialność twórców komponentów (poza szczególnie krytycznymi systemami) Testy wykonywane na podstawie doświadczenia twórcy Testy integracyjne Testowanie zbiorów komponentów zintegrowanych w większy system lub podsystem Odpowiedzialność niezależnego zespołu testerów Testy oparte na specyfikacji systemu
Testowanie defektów Celem testowania jest odkrycie defektów w programie Udany test defektów to taki, który sprawia, że program zachowuje się w nieoczekiwany sposób Testy pokazują obecność a nie brak defektów
Priorytety testowania Tylko wyczerpujące testowanie może pokazać, że program jest wolny od błędów. Niestety jest ono niepraktyczne, a niekiedy wręcz niemożliwe Testy powinny sprawdzać możliwości systemu a nie jego komponentów Testowanie starych możliwości jest ważniejsze od testowania nowych Testowanie typowych sytuacji jest ważniejsze od testowania warunków brzegowych
Dane testowe i przypadki testowe Dane testowe Dane, które są przekazywane do testowanego systemu Przypadki testowe Dane dla testowanego systemu i przewidywane odpowiedzi systemu zachowującego się w sposób zgodny ze specyfikacją
Proces testowania defektów Raport z testowania Przypadki testowe Dane testowe Wyniki testów Porównaj wyniki z przypadkami testowymi Opracuj przypadki testowe Przygotuj dane testowe Uruchom program na danych testowych
Testowanie czarnej skrzynki Podejście do testowania w którym program jest traktowany jako czarna skrzynka Przypadki testowe oparte są na specyfikacji programu Planowanie testowania rozpoczyna się we wczesnych fazach przedsięwzięcia
Dzielenie na klasy równoważności Dane wejściowe i wyniki można często podzielić na różne klasy w których znajdują się podobne doi siebie przypadki Dla danych w obrębie jednej klasy program zachowuje się podobnie Przypadki testowe powinny być wybrane z każdej z klas
Podział na klasy Błędne Wejścia Poprawne Wejścia System Wyjścia
Podział na klasy Podział danych wejściowych na ‘zbiory równoważne’ Jeśli wejście jest pięciocyfrową liczbą naturalną to klasami są: <10,000; 10 000-99 999; 99 999 > Warto wybrać następujące testy 00000, 09999, 10000, 99999, 10001
Specyfikacja wyszukiwania procedure Search (Key : ELEM ; T: ELEM_ARRAY; Found : in out BOOLEAN; L: in out ELEM_INDEX) ; Pre-condition -- the array has at least one element T’FIRST <= T’LAST Post-condition -- the element is found and is referenced by L ( Found and T (L) = Key) or -- the element is not in the array ( not Found and not (exists i, T’FIRST >= i <= T’LAST, T (i) = Key ))
Wyszukiwanie podział na klasy Dane spełniające warunki wejściowe Dane nie spełniające warunków wejściowych Dane gdzie klucz jest w tablicy Dane gdzie klucza nie ma w tablicy
Zasady testowania (listy) Testuj oprogramowanie na listach jednoelementowych Używaj list o różnych rozmiarach Napisz testy w których odnosisz się do pierwszego, środkowego i końcowego elementu listy Testuj listy puste
Wyszukiwanie - klasy
Testowanie strukturalne Czasami nazywane testowaniem białej skrzynki Przypadki testowe otrzymane na podstawie struktury programu. Znajomość programu pomaga odnaleźć dodatkowe przypadki Celem jest przetestowanie wszystkich instrukcji programu (ale nie wszystkich kombinacji ścieżek)
Binary search (Java)
Binary search – klasy równoważności Spełniony warunek wstępny, klucz w tablicy Spełniony warunek wstępny, klucz nie w tablicy Niespełniony warunek wstępny, klucz w tablicy Niespełniony warunek wstępny, klucz nie w tablicy Dane mają jeden element Dane mają parzystą liczbę elementów Dane mają nieparzystą liczbę elementów
Binary search – przypadki testowe
Testowanie ścieżek Celem testowania ścieżek jest zapewnienie, ze każda ścieżka programu jest wykonywana co najmniej raz Punktem wyjścia do testowania ścieżek jest graf przepływu sterowania w programie pokazujący decyzje i przebieg sterowania Instrukcje warunkowe są wierzchołkami grafu
Graf przepływu sterowania Opisuje przepływ sterowania w programie. Każda gałąź jest pokazana jako oddzielna ścieżka a pętle są pokazane jako zapętlone krawędzie Używany do liczenia złożoności cyklicznej Złożoność cykliczna = Liczba krawędzi – Liczba węzłów +2
Złożoność cykliczna Liczba przypadków testowych równa jest złożoności cyklicznej Złożoność cykliczna jest równa liczbie warunków logicznych w programie Należy używać ostrożnie, gdyż nie zawsze daje dobre rezultaty Nie wszystkie kombinacje ścieżek są wykonywane
Binary search flow graph
Niezależne ścieżki 1, 2, 3, 8, 9 1, 2, 3, 4, 6, 7, 2 1, 2, 3, 4, 5, 7, 2 1, 2, 3, 4, 6, 7, 2, 8, 9 Przypadki testowe należy dobrać tak, aby sprawdzić wszystkie ścieżki Analizator dynamicznego wykonania może być użyty dla zweryfikowania czy wszystkie ścieżki są przetestowane
Testy integracyjne Testują pełny system lub system złożony z gotowych komponentów Powinny być testami czarnej skrzynki z przypadkami opracowanymi na podstawie specyfikacji Główną trudnością jest zlokalizowanie błędów Przyrostowe testy integracyjne zwiększają szanse powodzenia
Przyrostowe testowanie integracyjne
Podejścia do testowana integracyjnego Testowanie zstępujące najpierw testuje się system z wysokiego poziomu stosując namiastki, które następnie zastępuje się działającymi komponentami Testowanie wstępujące Najpierw testuje się komponenty najniższego poziomu W praktyce stosuje się oba podejścia równocześnie
Testowanie zstępujące
Testowanie wstępujące
Porównanie metod testowania Zatwierdzanie architektury Testowanie zstępujące lepiej wykrywa błędy w architekturze Demonstracja systemu Testowanie zstępujące pozwala na szybszą demonstrację działającego systemu Implementacja testowania Łatwiej jest przeprowadzać testy wstępujące Obserwacja testów Problemy w obu przypadkach. Często trzeba tworzyć dodatkowy kod
Testowanie interfejsów Jest wykonywane po zintegrowaniu modułów lub podsystemów Celem jest wykrycie błędów programistycznych oraz nieuzasadnionych założeń Szczególnie ważne w przypadku programów obiektowych
Testowanie interfejsów
Rodzaje interfejsów Interfejsy parametryczne Dane przekazywane z jednej procedury do innej Interfejsy w pamięci dzielonej Blok pamięci dzielony pomiędzy podsystemami Interfejsy proceduralne Podsystem zawiera zbiór procedur wywoływany przez inny podsystem Interfejsy z przekazywaniem komunikatów Podsystem żąda usług od innego podsystemu
Błędy w interfejsach Niewłaściwe użycie interfejsu Komponent wywołujący inny komponent popełnia błąd używając interfejsu np. podając parametry w złej kolejności Niezrozumienie interfejsu Komponent wywołujący zawiera założenia o zachowaniu komponentu wywoływanego, które są nieprawdziwe Błędy synchronizacji Producent i konsument danych działają z różnymi prędkościami i odczytywana jest nieaktualna informacja
Porady Testuj procedury używając krańcowych wartości parametrów Zawsze testuj wskaźniki zawierające zera Projektuj testy, które spowodują sytuacje wyjątkowe Używaj testów obciążeniowych w przypadku systemów z przekazywaniem komunikatów W systemach z pamięcią dzieloną uważaj na porządek wykonywania działań
Testy obciążeniowe Testowanie systemów z obciążeniami na które systemy nie były zaprojektowane pozwala wykryć inne błędy Testy obciążeniowe sprawdzają obsługę błędów. Systemy nie powinny padać katastrofalnie. Nie powinny być tracone dane. Szczególnie istotne w przypadku systemów rozproszonych
Testowanie obiektowe Komponentami testowanymi są klasy i obiekty Obiekty mają zazwyczaj większą funkcjonalność niż pojedyncze metody, więc konieczna jest lepsza analiza źródeł Nie ma oczywistego wierzchołka w przypadku testów zstępujących
Poziomy testowania Testowanie poszczególnych operacji testowanie klas Testowanie gron obiektów Testowanie systemu obiektowego
Testowanie klas obiektów Pełen test klasy zawiera Testowanie wszystkich operacji związanych z obiektem Ustalanie i odczytywanie wszystkich atrybutów Badanie obiektu we wszystkich możliwych stanach Dziedziczenie sprawia trudności w testowaniu, gdyż informacje o obiekcie są porozrzucane po wielu miejscach
Interfejs stacji meteorologicznej Przypadki testowe dla wszystkich operacji Użycie diagramu stanów do znalezienia wszystkich stanów Przykładowe ciągi stanów Shutdown ® Waiting ® Shutdown Waiting ® Calibrating ® Testing ® Transmitting ® Waiting Waiting ® Collecting ® Waiting ® Summarising ® Transmitting ® Waiting
Integracja obiektów W systemach obiektowych poziomy integracji są słabiej widoczne Testowanie gron polega na testowaniu grup obiektów współpracujących ze sobą Do identyfikacji gron konieczna jest znajomość operacji związanych z tymi obiektami i funkcji systemu
Podejścia do testowania gron Testowanie scenariuszy lub przypadków użycia Testowanie jest oparte na interakcji z systemem Ma większy sens jeśli przypadków testowych dostarczają bezpośrednio użytkownicy Testowanie wątków Testowanie reakcji systemu na konkretne zbiory zdarzeń wejściowych Testowanie interakcji obiektów Testy polegają na śledzeniu interakcji pomiędzy obiektami od początku, aż do zakończenia przetwarzania
Testowanie oparte na scenariuszach Scenariusze tworzy się na podstawie przypadków użycia i uzupełnia o diagramy pokazujące interakcje pomiędzy obiektami użytymi w scenariuszu Rozważmy scenariusz zbierania danych o pogodzie
Zbieranie danych o pogodzie
testowanie stacji pogodowej Wątek wykonywanych metod CommsController:request ® WeatherStation:report ® WeatherData:summarise Wejścia i wyjścia Żądanie raportu, potwierdzenia i raport końcowy Może być testowane poprzez przygotowanie danych surowych i sprawdzenie czy są poprawnie podsumowywane Surowe dane mogą być używane do testowania obiektu WeatherData
Warsztaty do testowania Testowanie jest kosztowną częścią procesu tworzenia oprogramowania. Warsztaty do testowania udostępniają narzędzi do zredukowania całkowitego czasu i kosztów testowania Większość warsztatów jest narzędziami otwartymi Jest je trudno zintegrować z zamkniętymi narzędziami do analizy i projektowania
Warsztat testowy
Adaptowanie warsztatów testowych Tworzenie skryptów do obsługi interfejsu użytkownika i wzorów dla generatorów testów Oczekiwane wyniki mogą być przygotowane ręcznie do porównania z rzeczywistymi Można stworzyć specjalne programy do porównywania wyników
Główne tezy Ważniejsze jest testowanie części często używanych niż rzadko używanych Klasy równoważności to zbiory przypadków zachowujących się podobnie z punktu widzenia systemu Testowanie czarnej skrzynki jest oparte na specyfikacji testowanie strukturalne pomaga znaleźć przypadki, które przetestują wszystkie ścieżki przepływu sterowania
Główne tezy Miary pokrycia testów służą zapewnieniu, że wszystkie przypadki są testowane Błędy interfejsów powstają na wskutek nieporozumień w specyfikacji, błędów programistów i nieuzasadnionych założeń Aby przetestować klasę należy przetestować wszystkie metody, pola i stany Systemy obiektowe należy integrować wokół naturalnych gron