TESTOWANIE APLIKACJI KORPORACYJNYCH Autor: inż. Ewa ZYGA Promotor: dr inż. Marek MIŁOSZ 1. Rola przeprowadzania testów w procesie wytwarzania oprogramowania Po co testować? Odpowiedź jest prosta. Aby znaleźć błędy, aby upewnić się, że kod jest niezawodny, a czasem, aby sprawdzić, czy kod jest użyteczny. Testy dostarczają szczegółowych informacji, w jakim stopniu produkt jest niezawodny. Błędy wykryte i usunięte na etapie testowania są znacznie mniej kosztowne niż po uruchomieniu systemu, oraz, co się z tym nieodłącznie wiąże, znacznie zmniejszają ryzyko utraty zaufania klientów [3]. Rys. 1. Błędy znalezione poprawione w czasie trwania projektu Źródło: [5] Na rysunku 1przedstawiono liczbę błędów znalezionych i poprawionych w czasie trwania projektu. Gdy produkt staje się stabilny, liczba nowych błędów spada i wykres zaczyna przebiegać równolegle do osi poziomej [5]. W przypadku braku etapu testowania wykrycie błędów staje się dużo trudniejsze. Można rozróżnić różne typy testów w zależności od tego, jaki efekt chce się osiągnąć. Brian Marrick stworzył cztery kategorie powodów, dla których przeprowadzane są testy. Na 2012-02-09 Strona 1
jednej osi wykresu (rys. 2) znajdują się testy, które wspomagają pracę zespołu oraz testy krytykujące produkt. Druga oś dzieli testy na te skierowane na biznes oraz skierowane na technologie [3]. Rys. 2. Kwadranty testowania klasyfikacja testów Źródło: [3] Kolejność, w jakiej ponumerowane są ćwiartki nie mają związku z tym, kiedy różne typy testów są wykonywane. Na przykład, zwinny projekt rozpoczyna się od zadań klienta (czyli tych, na których klientowi najbardziej zależy), które mówią zespołowi, co programować, i te właśnie zadania pokrywa się kolejno testami. W pierwszym kwadrancie (rys. 2) wymienione są zautomatyzowane typy testów, testy jednostkowe, niekiedy zwane testami komponentów. Wykonanie tych testów w znacznym stopniu ułatwia wykonanie testów z pozostałych kwadrantów. W trakcie realizacji tych testów bardzo pomocne okazują się narzędzia do zarządzania kodem. Pozwalają one na powrót do poprzedniej wersji kodu, w przypadku, gdy okazuje się, że zmiany przyniosły szkody, jak również przechowują informacje, kto i jakie zmiany wprowadził. 2012-02-09 Strona 2
W drugim kwadrancie z rys. 2 znajdują się zarówno testy zautomatyzowane jak i manualne. Skierowane są na biznes i zakładają współpracę z klientami. Pomagają w zdefiniowaniu jakości i cech, których chce klient. W praktyce mogą to być testy funkcjonalne, ale również różnego typu symulacje czy prototypy. Aby dobrze wykonać ten typ testów należy je starannie zaplanować. Trzeci kwadrant (rys. 2) to testy wykonywane manualnie. Może to być np. sprawdzanie poprawności działania scenariuszy na bieżącej wersji aplikacji. Podstawowa ich cechą powinno być jak największe zbliżenie scenariuszy testowych do rzeczywistych sytuacji, wykorzystanie najbardziej prawdopodobnych parametrów. Innymi słowy są to testy akceptacyjne, które dają klientowi możliwość sprawdzenia nowych funkcji oraz wstępnie zaplanować, jakie funkcje dodać w przyszłości. Ostatni kwadrant to testy wydajnościowe i obciążeniowe. Pokazują jak szybko działa aplikacja, na ile jest stabilna oraz czy jest skalowalna. Pomagają wykryć tzw. wąskie gardła. W zależności od ważności problemu wydajności systemu testy te mogą być wykonywane od początku pracy nad projektem. Jak wiadomo, niemożliwe jest stworzenie programu idealnego już za pierwszym podejściem. Testy pomagają wykryć problemy w tworzonej aplikacji już w fazie programowania, co finalnie pozwala oddać klientowi produkt z akceptowalną liczbą błędów. Testy zwiększają jakość budowanego systemu, oraz ułatwiają jego rozwój sprawdzając czy nie złamano wymagań. Czas realizacji różnych typów testów zależy od ryzyka każdego projektu, celów klientów odnośnie produktu finalnego, tego czy projekt jest robiony na podstawie innego projektu czy tworzony jest od podstaw, a także kiedy źródło będzie gotowe do testowania [3]. 2. Wybrane typy testów 2.1. Testy jednostkowe Jako pierwsze zostaną omówione testy jednostkowe (ang. Unit Tests). Implementowane są one we wszystkich istniejących językach programowania. Powszechność ich stosowania sprawiła, że powstały dedykowane biblioteki ułatwiające tworzenie i wykonywanie tych 2012-02-09 Strona 3
testów. Testy jednostkowe to testowanie na najniższym poziomie. Poszczególne moduły, programy, klasy, obiekty, metody itd., czyli najmniejsze możliwe do przetestowania części oprogramowania, testowane są pojedynczo, w oderwaniu od reszty aplikacji. Takie podejście pozwala na sprawdzenie jednostki pod kątem zgodności ze zdefiniowanym typem/zakresem danych wejściowych [7]. Testy przeprowadzane są zazwyczaj dla przygotowanych wcześniej danych testowych i mają na celu wykrycie jak największej ilości błędów. Mogą one testować zarówno funkcjonalności modułów, jak i ich właściwości niefunkcjonalne. Możliwe są również testy odporności modułu na błędne dane lub akcje oraz testowanie strukturalne w celu osiągnięcia pokrycia rozgałęzień [2]. W programowaniu obiektowym podstawową jednostkę aplikacji stanowi klasa. Testy jednostkowe umożliwiają wykrycie wielu błędów w kodzie na etapie implementacji lub na początku fazy testowania. Piszą je zazwyczaj osoby, które zajmowały się implementacją danego fragmentu oprogramowania. Defekty są naprawiane natychmiast po znalezieniu, bez formalnego ich zgłaszania. Izolacja klas do testów jednostkowych może być jednak trudna do osiągnięcia. W dużych projektach programistycznych klasy te mogą wywoływać metody innych klas, które mają istotny wpływ na działanie jednostki. W takich wypadkach rozwiązaniem mogą być obiekty zastępcze zwane również obiektami pozornymi (ang. Mock). Są to specjalnie implementowane interfejsy, które są w stanie zastąpić problematyczne części kodu. Ich logika oraz implementacja powinna być najprostsza jak to tylko możliwe oraz niezależna od innych fragmentów testowanej aplikacji [1]. Testy jednostkowe są z założenia proste i szybkie w uruchomieniu. Dzięki temu ten typ testów jest łatwy do zautomatyzowania, a to z kolei umożliwia częste sprawdzanie, czy zmiany w kodzie nie powodują występowania błędów i ewentualne poprawki (są to tzw. testy regresyjne [8]). Testy te mogą być również uważane za formę specyfikacji i dokumentacji. Z powyższych powodów są szczególnie popularne w programowaniu ekstremalnym [6], a szczególnie w metodyce TDD (ang. Test-Driven Development) [8]. 2.2. Testy integracyjne Po przeprowadzeniu testów jednostkowych warto sprawdzić, czy moduły/klasy poprawnie współdziałają ze sobą. W tym celu stosuje się testy integracyjne. Pomagają one również określić interakcję z innymi częściami systemu (system operacyjny, system plików, sprzęt) oraz interfejsy do innych systemów [2]. 2012-02-09 Strona 4
Testy integracyjne mogą być wykonywane na kilku poziomach. Można wyróżnić między innymi testy integracyjne modułów, które sprawdzają interakcje między modułami aplikacji oraz testy integracyjne systemów, które sprawdzają interakcje pomiędzy różnymi systemami. Pierwsze z nich wykonuje się zaraz po testach jednostkowych. Są ich naturalnym rozszerzeniem i zwykle wykonywane są przy użyciu tych samych bibliotek i narzędzi. Natomiast testy integracyjne systemów mogą być wykonywane po zakończeniu testowania systemowego. Im większy jest zakres integracji tym trudniejsze jest określenie miejsce wystąpienia błędu [2]. Można wyróżnić trzy główne podejścia do testów integracyjnych: Od góry do dołu (ang. Top Down). Od dołu do góry (ang. Bottom Up). Metoda skokowa, nazywana również metodą wielkiego wybuchu (ang. Big Bang). W podejściu Top-Down, jako pierwsze testowane są moduły znajdujące się na najwyższym poziomie w hierarchii. Moduły znajdujące się poniżej zastępowane są zaślepkami. Po czym zaślepki zastępowane są modułami niższego poziomu i poddawane testowaniu. Moment, w którym przetestowane zostaną moduły na najniższym poziomie wyznacza koniec testowania. Takie podejście pozwala testować logikę aplikacji oraz przepływ danych. Wadą tego podejścia jest to, że elementy na najniższych poziomach są stosunkowo późno integrowane. W modelu od dołu do góry postępuje się odwrotnie niż w poprzednim przypadku. Pierwsze testowane są najniżej położone komponenty. Wyżej położone komponenty używają przetestowanych uprzednio modułów. Koniec testowania następuje po przetestowaniu komponentów znajdujących się na najwyższym poziomie. Wadą podejścia Bottom Up jest późne testowanie procesów wysokiego poziomu. Metoda skokowa zakłada przeprowadzanie testów w momencie łączenia wielu modułów bez przeprowadzanych uprzednio testów przyrostowych. W tym modelu błędy występujące w komponentach wykrywane są w bardzo późnej fazie projektu. Z powodu dużego zakresu integracji trudno jest wychwycić miejsce wystąpienia błędu, a nawet istnieje ryzyko przeoczenia błędów krytycznych. Trudno jest też określić stopień pokrycia aplikacji testami [7]. 2012-02-09 Strona 5
2.3. Testy systemowe i akceptacyjne Testy systemowe pozwalają sprawdzić, czy zintegrowany uprzednio system spełnia wszystkie wymagania funkcjonalne oraz systemowe [7]. Pomagają również określić czy wykryte błędy maja wpływ na stabilność aplikacji. Dla testowania systemowego środowisko powinno odwzorowywać w miarę możliwości jak najwierniej środowisko produkcyjne, tak, aby zminimalizować ryzyko niewykrycia błędów zależnych od jego specyfiki [2]. Testy akceptacyjne określają zgodność systemu z wymaganiami klienta. Klient wykonuje przypadki testowe na swoim środowisku pracy (produkcyjnym). Po akceptacji systemu zostaje on uruchomiony na środowisku produkcyjnym [7]. Celem testów akceptacyjnych nie jest znalezienie defektów, ale wykazanie poprawności działania testowanych funkcjonalności. Służą do oceny gotowości systemu do wdrożenia, choć nie koniecznie są ostatnią fazą testowania [2]. W tabeli 1 znajduje się porównanie głównych cech testów jednostkowych i integracyjnych. Tab. 1. Testy akceptacyjne a jednostkowe Źródło: [4] 2012-02-09 Strona 6
2.4. Testy funkcjonalne Testy funkcjonalne są odzwierciedleniem wymagań funkcjonalnych (opisanych w dokumentacji w formie przypadków użycia lub specyfikacji funkcjonalnej) i tworzone są przy współpracy zarówno programistów i testerów, jak i klientów i analityków systemu. Dotyczą one funkcji lub cech systemu i wykonuje się je na wszystkich poziomach testów. Testy te odnoszą się do zewnętrznego działania oprogramowania (tzw. test czarnej skrzynki). Do testów typu funkcjonalnego zaliczamy między innymi testowanie zabezpieczeń [2]. Testy funkcjonalne często nazywane są testami akceptacyjnymi, ponieważ poprawne ich przejście stanowi zazwyczaj kryterium akceptacji systemu przez klienta. 2.5. Testy niefunkcjonalne Wymagania klienta, których nie da się zakwalifikować jako wymagania funkcjonalne można zweryfikować za pomocą testów niefunkcjonalnych. Ten typ testów również można przeprowadzać na wszystkich poziomach testowania. W ich skład wchodzą między innymi [2]: testy wydajności, testy obciążenia, testy przeciążenia, testy użyteczności, testy współdziałania, testy utrzymywalności, testy niezawodności, testy przenaszalności. W [2] określono, że testowanie niefunkcjonalne odnosi się do testów niezbędnych do pomiaru charakterystyk systemu i oprogramowania, które dają się skwantyfikować na skali (np. czas odpowiedzi w testowaniu wydajnościowym). 2012-02-09 Strona 7
Literatura 1. Bukowski M., Paterek P., Obiekt pozorny. A może coś innego? Kierunek rozwoju testów jednostkowych, TESTER.pl 2007, nr 10 2. Certyfikowany tester. Plan poziomu podstawowego Wer. 1.0, przeł. Bereza- Jarociński B., Jaszcz W., Klitenik H., Nowakowska J., Sabak J., Seredyn A., Stapp L., Ślęzak P., Żebrowski Ł., SJSI, 2006 [dostęp: 8 lutego 2012], Dostępny w Internecie: <http://www.sjsi.org/webgears//files/sjsi/file/sylabus.pdf> 3. Crispin L., Gregory J.: Agile testing: a practical guide for testers and agile teams, Addison-Wesley, Indiana, 2009 4. Jureczko M., Testowanie oprogramowania, Politechnika Wrocławska, Dostępny w Internecie: <http://staff.iiar.pwr.wroc.pl/marian.jureczko/testy2.pdf> [dostęp: 8 lutego 2012] 5. Kochański P., Jak usprawnić proces testowania oprogramowania: procedury, metodologia i narzędzia., erudisprocess Management 2004-2009 6. http://abarczewski.blogspot.com/ 7. http://www.testowanie.net/testowanie/zakres_testow/ 8. Miłosz M., Borys M., Plechawska-Wójcik M., Współczesne Technologie Informatyczne. Metodyki zwinne wytwarzania oprogramowania, Politechnika Lubelska, Lublin, 2011 (dostępne również w Bibliotece Cyfrowej: http://bc.pollub.pl/dlibra/) 2012-02-09 Strona 8