Testowanie
Zbigniew Jurkiewicz, Instytut Informatyki MIMUW
Testowanie
Testowanie polega na uruchamianiu systemu lub aplikacji w kontrolowanych
warunkach i ocenie wyników. Należy uwzględnić zarówno normalne,
jak i anormalne warunki pracy.
Testujący powinni być nastawieni na pokazanie, że w programach istnieją
błędy, a nie na wykazanie poprawności programów.
Zasady [na podstawie Glenford J.Myers Software Reliability. Principles
and Practices]:
- Testowanie musi rozpocząć się od ustalenia celów.
- Dobre dane testowe to takie, które z dużym prawdopodobieństwem wykryją
nieznany dotąd błąd w programie, nie zaś takie, które pokażą, żę program
pracuje poprawnie.
- Jednym z najtrudniejszych problemów testowania jest decyzja kiedy je
zakończyć.
- Nie można testować własnego programu.
- Niezbędną częścią każdego testu jest opis spodziewanych wyników.
- Unikaj testów niepowtarzalnych.
- Pisz dane testowe obejmujące zarówno poprawne, jak i niepoprawne warunki
wejściowe.
- Pamiętaj o testach dla wartości granicznych.
- Nigdy nie zmieniaj programu po to, aby ułatwić testowanie.
Fazy testowania
Testy jednostkowe (unit tests):
- Pojedyncze moduły, klasy, grupy klas.
- Według diagramów i specyfikacji klas.
- Domena programisty.
Testy integracyjne:
- Sprawdza się, czy komponenty współpracują zgodnie ze specyfikacją
- Według diagramów komponentów i diagramów współpracy.
Testy systemu:
- System jako ,,czarna skrzynka''. Sprawdza się, czy dostarcza
funkcjonalność oczekiwaną przez użytkownika. Według diagramów przypadków
użycia.
- White box testing}: testowanie z wykorzystaniem znajomości
wewnętrznej budowy programu, np. aby przetestować wszystkie ścieżki.
Testy akceptacyjne u klienta. Sprawdza się zgodność systemu z wymaganiami.
Kombinacja trzech metod:
- testowania próbek (benchmark testing)
- testowania pilotowego
- testowania równoległego (z dotychczasowym systemem, porównywanie
wyników)
Specjalne odmiany testowania:
- Testowanie działania pod obciążeniem (stress testing):
- krótkotrwałe przeciążenia,
- dłuższa praca przy górnej granicy obciążenia.
- Testowanie odtwarzania po awariach (recovery testing).
- Testowanie konfiguracji: uruchamianie zestawów testowych na
różnych platformach (w tym różne wersje systemu operacyjnego, typy
monitora, interfejsu graficznego, procesora, kart sieciowych itp.).
- Testowanie instalacji i deinstalacji: uruchamianie skryptów
instalacyjnych na dowolnych (najlepiej obcych) komputerach.
- Testowanie lokalizacji: dla oprogramowania przewidzianego w kilku
wersjach językowych.
- Testowanie bezpieczeństwa: w jakim stopniu system jest chroniony
przed nieautoryzowanym dostępem (wewnętrznym lub zewnętrznym).
- Naive-user testing: użytkownik postępuje ściśle według
instrukcji.
Dodatkowe zalecenia
- Używać zestawów testów regresyjnych, zwłaszcza przy poprawkach.
- Testowanie regresji oznacza pełne uruchomienie wszystkich
(tzn. zarówno starych jak i nowych) po modyfikacji systemu.
- W przypadku GUI jest to kłopotliwe, ale są narzędzia, np. dla X-windows
jest to Xnee, zob.
www.gnu.org/software/xnee/www/index.html
- Organizację testowania w metodologiach obiektowych organizuje się często
wokół przypadków użycia.
- Dane wejściowe i wyjściowe należy dzielić na klasy równoważności.
Przykład: poszukiwanie elementu w tablicy.
- Przepuszczając oprogramowanie przez zestaw testowy, monitorować go
oprogramowaniem sprawdzającym wyciekanie pamięci, użycie
niezainicjowanej pamięci itp. błędy gospodarki pamięcią.
Automatyzacja testowania
Polega na tworzeniu skryptów testowych. Są to schematyczne
procedury, zawierające w treści wywołania akcji -- metod
pozwalających programowo sterować interfejsem użytkownika, np.
- dla
PushButton
:
Click()
--- akcja manipulacji
IsActive()
--- akcja sprawdzenia
- dla
TextField
:
SetText("Paweł")
GetText()
- dla
Radiobox
(zbioru przycisków), ScrolledList
:
Select("Semestr jesienny")
GetSelected()
Takie wywołanie jak Click()
sprawdza wiele rzeczy równocześnie, np.
- czy jest wyświetlony dialog zawierający przycisk i czy dialog ten jest
aktywny;
- czy przycisk istnieje, czy jest aktywny i czy mozna go nacisnąć.
Dodatkowe akcje do pisania skryptów, np. RaiseError("...")
.
Plany i skrypty
Plan testów jest to wykaz skryptów (scenariuszy) testowych wraz z opisem.
Skrypt to ciąg przypadków testowych, wynikiem każdego przypadku testowego
jest tak/nie (,,zdał/nie zdał'').
script Test-Application-Functionality() {
for each test-case in List-of-test-cases
do perform(test-case);
}
Przypadek testowy
Własności:
- Ma jeden cel (wymaganie).
- Rozpoczyna się i kończy w znanym stanie aplikacji (tzw. base
state).
- Jest niezależny od innych części planu testów.
Typowy schemat pojedynczego przypadku testowego:
- Ustanów stan bazowy
- Wykonaj akcje składowe
- Zweryfikuj wyniki
- Przywróć stan bazowy
Przykład przypadku testowego
Dla
DialogBox Student {
PushButton Add, Delete, Cancel, Help;
TextField Nazwisko, Indeks, Pesel;
Radiobox Rodzaj;
}
przypadek testowy mógłby wyglądać następująco
testcase Enter-Valid-Student(nazwisko, indeks, rodzaj) {
Student.Nazwisko.SetText(nazwisko);
Student.Indeks.SetText(index);
Student.Rodzaj.Select(rodzaj);
if Student.Add.IsActive()
then Student.Add.Click()
else RaiseError("Nie można dodać studenta, przycisk Add nieaktywny");
}
Testować należy nie tylko poprawne, ale także błędne odpowiedzi
testcase Enter-Invalid-Student(indeks, rodzaj) {
Student.Nazwisko.SetText(" ");
Student.Indeks.SetText(index);
Student.Rodzaj.Select(rodzaj);
if Student.Add.IsActive()
then RaiseError("Nie powinno akceptować pustego nazwiska");
}
Narzędzia do testowania
Warto korzystać z dobrych narzędzi
- analizatorów kodu; badają jego złożoność, zgodność ze standardami itp.
- analizatorów gospodarki pamięcią: przekroczenia granic, ,,wycieki'' pamięci.
- analizatorów stron WWW: poprawność dowiązań (,,linków''), zgodność ze
standardami (wiele przeglądarek jest zbyt liberalnych), bezpieczeństwo.