Testy, narzędzia do automatycznego testowania, metodologia testów

Krzysztof Dulęba
Krzysztof Dziołak
Tomasz Idziaszek
Tomasz Kazana

Motto

,,Jeśli budowniczy wybuduje dom dla mieszkańca i wykona jego konstrukcję tak słabą, że dom się zawali i spowoduje śmierć właściciela to budowniczy powinien być zabity. Jeśli zawalenie się domu spowoduje śmierć syna właściciela to należy zabić syna budowniczego. Jeśli przy zawaleniu domu zostanie zniszczone dobro to budowniczy ma wykonać to wszystko co zostało zniszczone ponieważ nie wybudował domu wystarczająco mocno, powinien więc odbudować go na własny koszt.''

— Kodeks Hammurabiego, ok. 1700 r. p.n.e, wg. dra inż. Bolesława Szomańskiego najstarszy dokument dotyczący jakości

Spis treści

Wstęp
Testowanie — szerokie pojęcie
Szacunkowe koszty błędu w różnych fazach projektu
Metodologie testowania
PREZENTACJA PROGRAMU JUNIT
Faza testowania w praktyce
Różne testy
Różne błędy
Kto testuje
Testy wydajności
PREZENTACJA PROGRAMU PERFORMANCE TEST
PREZENTACJA PROGRAMU TEST-COMPLETE
Testowanie wydajności — przykłady
Wnioski
PREZENTACJA PROGRAMU JMETER
PREZENTACJA PRZYKŁADOWEGO PRZEPROWADZENIA TESTÓW, ANALIZY I PREZENTACJI WYNIKÓW
Metoda kolorowania ryb
Techniki wyboru zestawów testowych
Co jeszcze można testować?
Znaczenie testowania
Warto testować
Nie warto testować
Ciekawe strony

Wstęp

Testowanie ma zapewnić jakość ostatecznego produktu. Trudność tego procesu w przypadku programowania jest nieporównywalna z niczym innym. Wymaga całościowej wizji tego procesu, oddzielnego zarządzania. W poważnych projektach za testowanie odpowiada zwykle oddzielna jednostka. Istnieja nawet firmy specjalizujace sie w testowaniu np. http://www.spnt.pl/. Należy sobie zdawać sprawę z oczywistych ograniczeń testowania. W przypadku programów dowód na nieistnienie błędu jest w zasadzie niemożliwy. W szczególności nie istnieją nawet deterministyczne metody dowodzenia poprawności programów współbieżnych. Można dowodzić poprawność pewnych modeli (np. zakładających ograniczenie liczby procesów jak w Model-Checkingu), ale i wówczas rząd trudności dowodu najczęściej przeważa nad trudnością samego problemu. Przybliżony koszt matematycznego dowodu poprawności to $500000 za 10 KLOC (Kilos Lines Of Code). Tak więc teoria testów musi — z natury rzeczy — być wiedzą opartą na przybliżeniach i niepewności.

Testowanie — szerokie pojęcie

Testowanie to eksperymentalne sprawdzenie stanu, jakości i sposobu działania programu. Ponieważ możliwych przebiegów programu jest nieskończenie wiele (gdy dopuścimy nieskończone wejście to nawet nieprzeliczalnie wiele!), to przeprowadzenie pełnego sprawdzenia jest niemożliwe.

Istnieją bardzo różne metodologie. Ich wspólnym celem jest wykrycie błędów i niezgodności z wymaganiami. Zanim jednak się tym zajmiemy warto przyjrzeć się temu, co w ogóle warto testować.

Otóż najbardziej ogólny podział wyróżnia testy funkcjonalne, efektywnościowe i testy odtwarzalności.

Testy funkcjonalne sprawdzają zgodność cech programu z założeniami. Testy efektywnościowe oceniają prędkość działania, natomiast testy odtwarzalnościowe odpowiadają na pytanie, czy z kopii zapasowej da się odtworzyć poprawnie działający system.

Szacunkowe koszty błędu w różnych fazach projektu

FazaKoszt
Analiza$1
Projekt$5
Kodowanie$10
Testy jednostkowe$15
Testy integracyjne$22
Testy systemowe$50
Po wdrożeniu$100+

Metodologie testowania

Do dziś wykształciły się bardzo różne recepty na przeprowadzanie testów. Ich porównywanie jest bardzo trudne, bo nawet trudno zdefiniować efektywność testowania.

Najważniejsze metodologie:

Faza testowania w praktyce

Różne testy

Testy możemy dzielić ze względu na bardzo różne kryteria podziału. Wspomnijmy tuo:

Różne błędy

Zwykle pisząc duży projekt przyjmujemy początkowo dopuszczalną liczbę błędów poważnych (najczęściej 2-3) i błedów drobnych (kilkanaście)

Kto testuje

Istnieją dwa zasadniczo różne podejścia. Albo testy wykonuje osoba niemająca pojęcia o programie albo specjalny program (który dostaje skrypty testowe). W obu przypadkach przydają się generatory losowych testów.

Testy wydajności

Testowanie wydajności zawsze oznacza porównywanie. Nawet jeśli mierzymy czas działania to tak naprawdę porównujemy go z czasem w jakim trwa 9192631770 razy przejście między dwoma poziomami struktury nadsubtelnej stanu podstawowego nuklidu cezu (tzn. z 1 sekundą). Nie ma przecież żadnej uniwersalnej jednostki wydajności. (W przypadku błędów funkcjalnych możemy je po prostu liczyć, grupując nawet na dość ściśle zdefiniowane grupy.) Oznacza to konieczność — przy każdym teście wydajnościowym — dokładnego określenia jaką cechę porównujemy.

PREZENTACJA PROGRAMU PERFORMANCE TEST

Problem testowania wydajności wynika z faktu ogromnego skomplikowania komputera. Ilość czynników jest tak duża, że bardzo trudno powiedzieć, który komputer czy program jest wydajniejszy od drugiego podobnego. To często zależy od zastosowań. Rozważmy dla przykładu twardy dysk. Możemy rozważać np. prędkość zapisu i odczytu. Dla celów archiwizujących bardziej wydajny będzie dysk z szybkim zapisem, natomiast dla firmy, która ma obraz systemu często używany do kopiowana na nowe komputery, ważniejszy jest odczyt.

Testy wydajnościowe przede wszystkim dzielimy na syntetyczne i aplikacyjne. Te pierwsze oceniają jakiś bardzo konkretny aspekt, np. Whetstone z 1972 Hurolda Curnowa, który testował operacje zmiennoprzecinkowe. Takie podejście jest bardzo delikatne, gdyż należy możliwie odizolować się od czynników zewnętrznych. W szczególności w/w przypadek jest mało adekwatny, bo nie uwzględnia obecności cache'u procesora, który sztucznie polepsza wyniki. Główną wadą testów syntetycznych to właśnie fakt, że testy są mało związane z codzienną pracą użytkownika. W szczególności podawanie wydajności systemu jako średniej różnych testów syntetycznych jest pozbawione sensu, bo nie uwzględnia statystyki wykonywania różnych operacji.

Testy aplikacyjne starają się radzić z tym problemem — tzn. testy są tak przygotowane, aby możliwie symulowały pracę użytkownika, czy wręcz mierzą jakieś cechy prawdziwych programów. Np. bardzo użytecznym testem aplikacyjnym jest liczenie wyświetlanych klatek na sekundę w ulubionej grze komputerowej. Testy aplikacyjne są bardzo trudne do opracowania, ale mają tę zaletę, że w miarę wymiernie oceniają cały program/system. Przykład: 3DMark do oceny grafiki 3D. Innym testem aplikacyjnym może być kompilacja jądra — operacje wykonywane w tym zadaniu dość dobrze przybliżają działanie systemu.

PREZENTACJA PROGRAMU TEST-COMPLETE

Wniosek: najtrudniej wymyślić dobry scenariusz testowy, mierzenie łatwe.

Testy wydajnościowe możemy także dzielić na niskopoziomowe — badające np. prędkość transmisji danych z pamięci do procesora (te są z natury syntetyczne) bądź wysokopoziomowe — np. badające czas otworzenia i odczytania pliku (taki test uwzględnia wiele aspektów architektury jak: stacje dysków, OS, pamięć itp.)

Przy każdym teście wydajnościowym pamiętajmy, że samo badanie wpływa na wynik i jest to jedna z głównych przyczyn błędów pomiarowych.

Cechy porawnego testowania wydajności:

Testy programu najlepiej wykonać na kilku architekturach i systemach (w tym na ,,gołym systemie'') i wyniki podawać zbiorczo. Najczęściej wyróżniamy także operację dominującą (np. ściągnięcie 1 bajta danych) i czas podajemy uśredniony dla jednej takiej operacji. Tzn. porównanie czasu ściągnięcia 1mb danych z czasem ściągnięcia 100kb z innego serwera nic nie mówi, ale uśredniony wynik dla wspólnej pojemności jest odpowiedni.

Testowanie wydajności — przykłady rozwiązań (na podstawie materiałów firmy DELL)

Wnioski

TestowanieFunkcjonalnościWydajności
Określenie celówŁatwe (sprawdzenie zgodności ze specyfikacją)Trudne (co to znaczy że nasz program jest wydajny?)
PrzeprowadzenieTrudneŁatwe (zmierzenie tego co określają cele)
Waga procesie pisania programówNiedocenianaNiedoceniana

PREZENTACJA PROGRAMU JMETER

PREZENTACJA PRZYKŁADOWEGO PRZEPROWADZENIA TESTÓW, ANALIZY I PREZENTACJI WYNIKÓW TESTOWYCH

Metoda kolorowania ryb

Dwóm testerom zlecamy sprawdzanie programu. Jeden wykrył 100 błędów, drugi 120, przy czym część wspólna wynosi 80. Jak oszacować łączną liczbę błędów? Otóż:

Myślmy o błędach w programie jak o rybach w stawie. Pierwszy rybak wyłowił X ryb, wszystkim pokolorował płetwy i z powrotem wrzucił do wodu. Kolejnego dnia inny rybak złowił Y ryb, ale K z nich była oznaczona. Zakładając dokładne wymieszanie ryb (czyli de facto, że błędy są jednakowo wykrywalne) mamy że kolorowe ryby stanowią K/Y wszystkich ryb — bo łowiąc za drugim razem nie wyróżnialiśmy żadnego typu ryb. Stąd: X ryb stanowi K/Y wszystkich, a więc łącznie w stawie jest (X*Y) / K ryb. U nas: błędów znajduje się około (100 * 120) / 80 = 150.

Techniki wyboru zestawów testowych

Co jeszcze można testować?

Testowanie to niezwykle szeroki temat. Pewne rodzaje testów nie są omówione tu szczegółowo, podajemy tylko ich przegląd:

Testy użyteczności oceniają takie aspekty jak;

Testy bezpieczeństwa sprawdzają bezpieczenstwo (nie wydajność!) danych przy niekorzystnych warunkach takich jak: Testy odporności - sprawdzają działanie programu przy warunków uniemożliwiających dalszą pracę, takich jak:

Znaczenie testowania

W świetnym artykule ,,Testowanie oprogramowania — niechciane dziecko technologii informatycznych'' (27 stycznia 1997 r., ComputerWorld) Wojciech Gryciuk powołuje się na bardzo znamienne dane statystyczne: procentowa liczba błędów w aplikacjach komputerowych nie zmienia się od 15 lat. W połączeniu z faktem, że ilość linii kodu rośnie geometrycznie, daje to zatrważający obraz lawiny błędów otaczającej nas z każdej strony. Tylko bardzo usystematyzowany proces testowania może temu przeciwdziałać.

Dla zobrazowania ogromu kodu wokół nas przytoczmy jeszcze inne dane: współczesny samochód jest oprogramowany przez 80 KLOC (KLOC = Kilos Lines Of Code, tysiące linii kodu), a współczesny telewizor przez 150 KLOC!

Znaczenie procesu testowania jest tak duże, że już nie tylko w firmach powstają specjalne jednostki testerów (co niegdyś było rzadkością), ale także oddzielne firmy specjalizujące się w testowaniu.

Warto testować

Cel testowania wydaje się oczywisty i wręcz niewarty roztrząsania. To zapewne prawda, a mimo to bardzo wiele programów nie zostaje należycie przetestowanych. Dlaczego? Sądzę, że często błędy programów wynikają ze swoistej próżności programisty: przecież programista ma za zadanie napisać poprawny program, a po co testować poprawny program?

Tak więc praktyka gruntownego testowania może się wykształcić po przełamaniu pewnej bariery psychologicznej. Po dopuszczeniu myśli o niedoskonałości swej pracy.

Nie warto testować

Testowanie, jak każda faza projektu wiąże się z pewnymi wymiernymi kosztami. Stąd nie zawsze dalsze testowanie opłaca się, często amortyzuje je zysk z wcześniejszego wejścia na rynek. Odwołajmy się do porównania z mniej abstrakcyjnym rynkiem: być może droższe jest wyprodukowanie 1000 sztuk dobrych na 100% lodówek, niż wyprodukowanie 1000 sztuk, z których 5% jest wadliwa nawet wliczając koszt naprawy tych trefnych 50. Podobnie z testowaniem: często celowo wypuszcza się na rynek produkt ze znanymi bugami, żeby już na siebie zarabiał. Koszt wypuszczania łatek (patch'y) jest amortyzowany przez zysk ze sprzedaży. Oczywiście takie postępowanie wiąże się — przy poważnych błędach — z utratą wiarygodności. Należy więc umiejętnie dobrać akceptowany poziom drobnych błędów. Decyzja jest tu trudna, ale przecież w biznesie najczęściej decydują subtelności...

Ciekawe strony