Automatyzacja procesu testowania warstwy prezentacji

Nikogo już chyba nie trzeba przekonywać, że testowanie aplikacji przed wprowadzeniem na rynek jest niezbędne. Robią tak wszystkie szanujące się firmy, dbające o reputację i stan konta. Wymierne korzyści wynikające z wplecenia procesu testowania w proces tworzenia aplikacji (ang. test driven development) są przedmiotem wielu opracowań i stają się udziałem coraz większej ilości firm stosujących metodologię zwinnego zarządzania projektami (ang. agile methodologies). Proces testowania jest coraz częściej nieodłącznym elementem procesu budowy aplikacji, co jest z powodzeniem realizowane poprzez narzędzia wspierające budowę aplikacji.
Testowanie aplikacji jest procesem żmudnym, podatnym na błędy oraz wymaga częstego powtarzania; naturalne jest zatem dążenie do zautomatyzowania tego procesu. Automatyzacja taka jest możliwa w różnym stopniu dla różnego rodzaju testów. Stosowane powszechnie testy jednostkowe pozwalają na zautomatyzowanie badania poprawności działania pojedynczej klasy (a dokładnie działania zgodnego ze stworzonym zestawem testów). Wykorzystywane w tym procesie biblioteki JUnit, TestNG czy NUnit są również często używane do testowania bardziej złożonego kodu kompletnych komponentów uruchamianych w lub poza kontenerem. Proces tworzenia i automatyzacji takich testów jest powszechnie znany.
Najwięcej trudności sprawia testowanie graficznych interfejsów użytkownika. Testowanie GUI, czyli warstwy prezentacji aplikacji, polega bardzo często na jej ręcznym przeklikiwaniu przez coraz bardziej znudzonych testerów. Jest to zajęcie czasochłonne, żmudne, podatne na błędy, niezbyt efektywne, a przy braku dobrej organizacji pracy oraz repozytorium scenariuszy testowych, praktycznie nieweryfikowalne. Trudno uważać takie rozwiązanie za dobre – proces testowania warstwy prezentacji również warto zautomatyzować, choć nie jest to łatwe, a często wydaje się prawie niemożliwe.

Korzyści i problemy automatyzacji procesu testowania GUI

Automatyzacja procesu testowania graficznego interfejsu użytkownika (ang. GUI graphical user interface) może dostarczyć wielu korzyści. Najważniejsze z nich to:
• powtarzalność testów – a więc możliwość wielokrotnego odtwarzania identycznych sekwencji testów;
• kompletność wykonania – testy wykonują się dokładnie, tak jak zostały zdefiniowane (bez, często stosowanych przy ręcznym testowaniu, uproszczeń scenariuszy);
• skrócenie czasu testowania – z reguły wykonują się o wiele szybciej niż potrafi to zrobić tester, nie potrzebują przerw i bez protestu wykonują się „po godzinach”;
• wykrywają więcej „drobnych błędów”, czyli takich, które łatwo jest przeoczyć testerowi;
• „zmuszają” do systematycznego budowania repozytorium testów, czyli zestawu testów rozszerzanego o nowe funkcje aplikacji oraz nowe przypadki błędnego działania;
• gwarantują zgodność funkcjonalności w kolejnej wersji aplikacji poddanej zmianom (ang. Refactoring);
• niższy koszt – automatyzacja testów jest jedną z najszybciej zwracających się inwestycji w firmie (i to uwzględniając wyłącznie redukcję wydatków ponoszonych bezpośrednio na testerów).
Podstawowym problemem pozostaje jednak sposób tworzenia, uruchamiania oraz utrzymania testów. Testy bowiem, podobnie jak aplikacja, wymagają utrzymania, czyli dostosowania do zmian wprowadzanych w aplikacji. Najbardziej znanym podejściem tworzenia zestawu testów jest nagrywanie akcji wykonywanych przez testera, tak by mogły być one następnie powtórzone bez jego udziału. Aplikacja testująca przechwytuje i zapamiętuje ruch myszki oraz zdarzenia generowane przez klawiaturę; tak przygotowany test może być odtwarzany bez udziału człowieka. Atrakcyjność tego podejścia w znacznym stopniu ograniczają następujące fakty:
• test może być poprawnie odtworzony wyłącznie przy tej samej rozdzielczości ekranu, czcionek i na tym samym systemie operacyjnym, na którym był przygotowany (w innym przypadku kliknięcia mogą wystąpić w miejscach przypadkowych, co sprawi, że przebieg testu będzie zdecydowanie odbiegał od zamierzonego);
• poprawienie testu jest najczęściej niemożliwe – musi on być najczęściej nagrywany od początku;
• nie można w prosty sposób weryfikować czy za-wartość wyświetlanych przez aplikację okienek jest zgodna z oczekiwaną.

Powyższe problemy narastają jeśli rozważy się warstwę prezentacji aplikacji opartą na WWW. Wykorzystanie aplikacji poprzez przeglądarkę internetową jest coraz popularniejsze i już od kilku lat tworzone są biblioteki pomagające w ich testowaniu. Najbardziej znane, otwarte narzędzia dla środowiska Java to HttpUnit lub HtmlUnit. Większość z nich działa na podobnej zasadzie: symuluje klienta http. Aplikacja testująca wysyła żądanie dostępu do konkretnego adresu (zarówno metody POST jak i GET) oraz parsuje przychodzące od serwera odpowiedzi w poszukiwaniu wymaganych danych. Podejście takie jest wystarczające dla bardzo prostych aplikacji. Problemy pojawiają się przy próbie wykorzystania w stronach języka JavaScript, osadzenia kontrolki albo apletu. Równocześnie nawet pozytywne wykonanie wszystkich testów nie gwarantuje, że aplikacja będzie poprawnie działać dla konkretnej kombinacji: system operacyjny/przeglądarka. W rzeczywistości bowiem przetestowana została zgodność aplikacji z konkretnym narzędziem testującym, a nie z przeglądarką.
Automatyzacja testowania graficznych interfejsów aplikacji, w tym interfejsów opartych na WWW nie jest rzeczą prostą. Istnieje jednak narzędzie, które może ten proces znacznie ułatwić – jest to oprogramowanie Squish firmy Froglogic.

Koncepcja oprogramowania Squish

Squish jest zaawansowanym narzędziem do automatycznego testowania graficznego interfejsu użytkownika. Rozwiązanie to lokuje się pomiędzy wspomnianą wcześniej aplikacją rejestrującą ruch myszki i akcje wykonywane na klawiaturze oraz narzędziem symulującym klienta http. Squish łączy zalety obu podejść. Działa ponad graficznym interfejsem użytkownika, lecz w sposób bardziej inteligentny od aplikacji rejestrującej ruch myszki i klawiatury. Squish nagrywa akcje wykonywane podczas używania/testownia aplikacji, nie rejestruje jednak współrzędnych punktów, w których wystąpiło kliknięcie. Identyfikuje on wykorzystywane komponenty interfejsu użytkownika (np. lista rozwijana, przycisk itp). Umożliwia to uruchomienie testu przy innych ustawieniach komputera niż podczas nagrywania, na zupełnie innej maszynie oraz uodparnia na sytuację przestawiania komponentu w ramach konkretnego widoku GUI.

obraz

Rysunek 1. Ogólna architektura działania oprogramowania Squish


W czasie testowania wykorzystywane są dwa główne elementy: badana aplikacja (AUT) oraz skrypt, który ją testuje. Podstawowa zasada jest taka, że skrypt oraz AUT uruchamiane są zawsze na dwóch niezależnych procesach. Dzięki temu nawet błędne działanie AUT nie pociąga za sobą problemów z poprawnym wykonywaniem skryptu. Inną korzyścią wynikającą z tego rozwiązania jest fakt, iż pozwala ono na stworzenie repozytorium testów przechowywanego w pewnej głównej lokacji i zdalne testowanie aplikacji na innych maszynach. Jest to rozwiązanie szczególnie użyteczne podczas testowania GUI. Komunikację między skryptem, a AUT obsługuje serwer Squish. Skrypt testujący wykonywany jest za pomocą narzędzia squishrunner, natomiast AUT do połączenia z serwerem wykorzystuje odpowiednią bibliotekę (hook library) – Rysunek 1. Z perspektywy twórcy testów separacja taka nie musi być widoczna. W przypadku korzystania z graficznego środowiska Squish IDE do nagrywania i wykonywania testów komponenty używane są w uproszczony sposób, pokazany na Rysunku 2.

obraz
Rysunek 2. Uproszczona architektura działania Squish z wykorzystaniem Squish IDE

Squish for Web

Squish for Web to edycja Squish pozwalająca na testowanie aplikacji webowych, w tym aplikacji wykorzystujących technologię Ajax. Squish for Web umożliwia testowanie stron www zawierających kombinację (D)HTML i JavaScript, a także dynamicznych i interaktywnych elementów (np. Struts menu). Squish wykorzystuje różne sposoby identyfikacji elementów HTML i DOM, co pozwala na tworzenie testów bez potrzeby modyfikacji badanej aplikacji.

Nagrywanie testu

Instalacja Squish za pomocą dołączonego instalatora jest bezproblemowa, do nagrywania testów można przystąpić zaraz po jej zakończeniu. Aby nagrać pierwszy test należy utworzyć grupę testów (ang. test suite). Robi się to przy użyciu prostego kreatora, który umożliwia wybór języka skryptowego dla należących do grupy testów oraz miejsca, w którym zostanie ona zapisana. Odpowiedni podział testów ułatwia późniejsze sprawdzanie poprawności działania jedynie wybranych testów, obejmujących wybrane funkcje testowanej aplikacji. Ustalone przez użytkownika nazwy grup i testów są automatycznie uzupełniane o prefiksy, odpowiednio suite lub tst. Do grupy testów dodajemy testy, które są tworzone przez nagrywanie akcji użytkownika.
Zanim rozpocznie się nagrywanie akcji, Squish poprosi o wybór metody synchronizacji. Trzeba zdecydować czy czasy oczekiwania na obiekty mają być stałe przy każdym odtwarzaniu, czy wykorzystana ma być funkcja waitForObject, która pozwala wstrzymać odtwarzanie nagranych akcji do momentu, aż obiekt osiągnie gotowość (pozwala to uniknąć sytuacji, w której w trakcie odtwarzania testu wykorzystywane są komponenty GUI, które nie zostały jeszcze do końca załadowane/zainicjalizowane). Wybór synchronizacji znajduje odzwierciedlenie w otrzymanym po nagraniu skrypcie. Najwygodniejszym podejściem jest nagranie testów z opcją „snooze”, która ustawia odstępy między akcjami na konkretną wartość czasu, a następnie, już w trakcie edycji skryptu, wstawienie funkcji waitForObject w pewnych krytycznych miejscach, w których czas ten jest niewystarczający, bądź zmienny. Przed rozpoczęciem nagrywania należy również określić czy obiekty mają być identyfikowane po jednym czy po wielu parametrach i oczywiście podać URL, wskazujący aplikację, która ma być testowana. Kiedy wszystkie opcje są już ustawione można zatwierdzić wybór i po otwarciu okna przeglądarki rozpocząć „przeklikiwanie” aplikacji. Nagrywanie testu możemy w dowolnym etapie zatrzymać lub zakończyć, umożliwia to niewielkie menu Squish, dostępne w trakcie, gdy test jest nagrywany. W momencie kliknięcia używane obiekty są identyfikowane i dodawane do mapy obiektów, a skrypt rozszerzany jest o zarejestrowaną akcję – Rysunek 3.

obraz

Rysunek 3. Mapa obiektów
Każdy obiekt w mapie obiektów ma dwie nazwy: prawdziwą – zawierającą parametry, po których został zidentyfikowany, oraz symboliczną, pod którą występuje w skrypcie. Dzięki temu, jeżeli któryś z parametrów obiektu z pewnych przyczyn ulegnie zmianie wystarczy zmodyfikować jeden wpis w mapie obiektów, aby przywrócić poprawność testu. Po wykonaniu wszystkich zaplanowanych czynności można zakończyć nagrywanie i przyjrzeć się bliżej otrzymanemu skryptowi – Listing 1. Skrypt jest na tyle czytelny, że jego edycja już po nagraniu nie powinna przysporzyć trudności.

Listing 1. Skrypt testujący bezpośrednio po nagraniu

function main() {<br /> loadUrl(”:https://localhost:8443/xtrf/”);<br /> waitForContextExists(”:index.html.FRAME2”);<br /> waitForObject(”:loginForm.j_username_text”);<br /> setFocus(”:loginForm.j_username_text”);<br /> waitForObject(”:loginForm.j_username_text”);<br /> setText(”:loginForm.j_username_text”,”admin”);<br /> waitForObject(”:loginForm.j_password_password”);<br /> setText(”loginForm.j_password_password”,”admin”);<br /> waitForObject(”loginForm.Login »_submit”);<br /> clickButton(”loginForm.Login »_submit”);<br /> waitForObject(”:divoCMenu0_0_DIV”);<br /> mouseClick(”:divoCMenu0_0_DIV”, 16, 13);<br /> waitForObject(”:System values_DIV”);<br /> mouseClick(”:System values_DIV”, 20, 6);<br /> waitForObject(”:Person position_DIV”);<br /> mouseClick(”:Person position_DIV”, 10, 7);<br /> waitForObject(”:btnCreateItem_DIV”);<br /> mouseClick(”:btnCreateItem_DIV”, 90, 10);<br /> waitForContextExists(”:create.do”);<br /> waitForObject(”:[object HTMLInputElement].name_text”);<br /> setFocus(”:[object HTMLInputElement].name_text”);<br /> waitForObject(”:[object HTMLInputElement].name_text”);<br /> setText(”:[object HTMLInputElement].name_text”, ”new_position”);<br /> waitForObject(”:btnSave_DIV”);<br /> mouseClick(”:btnSave_DIV”, 6, 6);

Dodanie warunków sprawdzających poprawność

Zapisany skrypt jest teoretycznie od razu gotowy do użycia, tzn. można go uruchomić w celu testowania aplikacji bez modyfikowania go. Jeżeli skrypt nie wykona się w całości może to świadczyć o tym, że testowana aplikacja nie działa właściwie. Należy się jednak zastanowić czy fakt, iż podczas odtwarzania testu nie pojawił się komunikat o błędzie wystarczy by stwierdzić, że aplikacja działa poprawnie. Oczywiście nie. Aby wnioskować o poprawności działania nie wystarczy wiedzieć, czy wszystkie nagrane akcje wykonały się, trzeba dodatkowo stwierdzić, że przyniosły one oczekiwany efekt, w szczególności poprzez weryfikację zawartości wyświetlanych w czasie testu okienek. Mógłby to robić tester śledząc wykonanie testów, ale wtedy trudno byłoby nazwać takie testy automatycznymi.
Squish pozwala przeprowadzić weryfikację poprawności zawartości testowanych elementów GUI, dzięki mechanizmom umożliwiającym sprawdzanie ich stanu. Robi się to poprzez wstawianie do testowanego skryptu punktów weryfikacji. Możliwe jest automatyczne rozszerzenie skryptu, poprzez wskazanie elementów GUI oraz wybór takich ich właściwości, których stan ma być każdorazowo sprawdzany. Skrypt można również bardzo łatwo rozszerzyć ręcznie, np. wykorzystując funkcje test.compare lub test.verify. Możemy dzięki temu zweryfikować np. czy jeśli nie zostało wypełnione obowiązkowe pole formularza testowana aplikacja zwróciła formularz ponownie, ale z odpowiednim komunikatem oraz czy zawartość pól wypełnionych poprawnie nie została utracona. Weryfikacja będzie przeprowadzona automatycznie dla każdego pola nawet bardzo długiego formularza.

Odtwarzanie testu

Gdy test jest nagrany oraz dodano warunki sprawdzające poprawność można przejść do wykonania testu. Aby uruchomić test wystarczy wcisnąć przycisk, który wywoła odtwarzanie zaznaczonych testów z wybranej ścieżki. Squish otwiera okno wybranej w ustawieniach przeglądarki i wykonuje wszystkie nagrane akcje oraz sprawdza warunki poprawności. Bardzo przydatna jest możliwość tworzenia skryptów pozwalających na konfigurację uruchamianych testów. Dzięki temu możliwe jest wybranie interesujących grup testów oraz określenie pliku, do którego zapisywane będą raporty. Dla wykonanego zestawu testu tworzony jest raport, w którym zawarta jest informacja o powodzeniu konkretnego testu oraz czasie wykonania – Rysunek 4. Działanie testowanej aplikacji www może się nieco różnić w zależności od używanej przeglądarki. Sqiush for Web pozwala na sprawdzanie jak aplikacja zachowuje się na różnych przeglądarkach, bez konieczności tworzenia różnych wersji testów na różne przeglądarki.

obraz

Rysunek 4. Okno raportu wykonania testów


Skrypt testujący nagrany z wykorzystaniem konkretnej przeglądarki, może być odtwarzany na innych przeglądarkach, bez żadnych dodatkowych modyfikacji. Skrypt taki, nagrany za po59www.sdjournal.orgSoftware Developer’s Journal 1/2008mocą Firefoxa, można bez problemu uruchomić używając Internet Explorera; wystarczy wybrać opcję, która decyduje o tym, jaka przeglądarka będzie wykorzystywana przy wykonywaniu testu. Podejście takie umożliwia efektywne testowanie zgodności aplikacji z wieloma różnymi przeglądarkami. Możliwe jest również stosowanie instrukcji warunkowej, która pozwala na wykonywanie różnych fragmentów skryptu dla różnych przeglądarek.
Testy Squish są niezależne również od systemu operacyjnego. Raz stworzony test może być z powodzeniem wykonywany w różnych systemach operacyjnych i to bez względu na to, w jakim systemie operacyjnym i na jakiej przeglądarce został stworzony. Squish for Web wspiera uruchamianie i nagrywanie testów dla aplikacji webowych przy użyciu przeglądarek Microsoft Internet Explorer, Mozilla, Firefox, Apple\\\‘s Safari i KDE\\\’s Konqueror na systemach Windows, Linux, Unix oraz Mac OS X.
W trakcie uruchamiania testów należy bezwzględnie pamiętać o zależności testowanej aplikacji od stanu bazy danych, którą ona wykorzystuje. Jeżeli w czasie testu tworzone i zapisywane do bazy danych są nowe dane (powstałe np. poprzez wypełnienie jakiegoś formularza), to każdorazowe uruchomienie testu będzie wiązać się z dodaniem tych samych danych – może to naruszać więzy integralności związane z unikalnością danych (np. nazwa klienta, nr faktury itp.). Jeżeli podczas testowania korzystamy z danych zapisanych w bazie danych wcześniej, to pamiętać trzeba o tym, aby dane użyte podczas nagrywania testu znajdowały się tam również podczas jego odtwarzania. Przykładowo, przy wykorzystywaniu list stronicowanych, zdarza się, że wymagane dane (np. nowo dodany wpis) w zależności od stanu bazy danych znajdują się na różnych stronach i nie są prawidłowo odnajdywane przez skrypt testujący i sygnalizowany jest błąd wykonania. Rozwiązaniem jest usuwanie nowo dodanych wpisów w ramach testu, bądź odtwarzanie początkowego (sprzed testów) stanu bazy danych każdorazowo przed rozpoczęciem testowania.
Squish jest stosunkowo odporny na dokonywanie zmian w GUI testowanej aplikacji. Poszczególne pola mogą być przestawiane w ramach formatki, można dodawać nowe pola oraz elementy kontrolne, a zmiany te nie wpływają na poprawność wykonywania testów. Należy oczywiście pamiętać o uwzględnieniu nowych elementów w skrypcie, bo tylko wtedy testowana będzie poprawność ich działania.

Wsparcie dla innych rodzajów GUI

Twórcy Squish zadbali o wygodę i przyzwyczajenia użytkowników. Tworzony kod testu może być zapisany w różnych językach skryptowych; wybierać można pomiędzy językami Python, JavaScript i Tcl. Rozszerzanie nagranego skryptu pozwala na dodanie wielu ciekawych funkcji i bywa czasem niezbędne.
Squish nie został stworzony jedynie z myślą o testowaniu aplikacji webowych. Jego różne wersje pozwalają na automatyczne testowanie aplikacji zbudowanych w oparciu o różne technologie warstwy prezentacji. Squish for Qt pozwala tworzyć testy aplikacji stworzonych z wykorzystaniem biblioteki Qt przeznaczonej do projektowania GUI w języku C++. Squish for Java współpracuje z aplikacjami zbudowanymi przy użyciu bibliotek graficznych dla środowiska Java, takich jak SWT (ang. Standard Widget Toolkit), Swing, RCP/Eclipse oraz AWT (ang. Abstract Windows Toolkit). Squish for Tk przeznaczony jest do współpracy z zestawem narzędzi graficznych Tk, opracowanym jako pakiet języka Tcl. Squish for KDE to specjalna, dostępna bez opłat edycja Squish for Qt, pozwalająca na tworzenie automatycznych testów GUI dla dystrybuowanych na otwartej licencji aplikacji KDE (Open Source/Free Software KDE applications). Squish for XView oraz Squish for 4Js oferują wsparcie odpowiednio dla XView oraz klientów Four J\\\’s Genero. Istnieje także wersja Squish Educational przeznaczona dla uniwersytetów i innych instytucji zajmujących się edukacją, umożliwiająca studentom zdobycie praktycznego doświadczenia związanego z testowaniem graficznych interfejsów użytkownika.

Podsumowanie

Wszystkich funkcji Squish nie sposób opisać w jednym artykule; można się z nimi zapoznać na stronie producenta oraz dzięki dołączonemu do programu obszernemu podręcznikowi użytkownika, który je szczegółowo opisuje i pomaga rozwiązać wiele problemów. Kilkumiesięczna praktyka stosowania Squish przyniosła wymierne korzyści. Zamieniła nastawienie do procesu testowania GUI aplikacji; nie jawi się on już jako bezproduktywne i niezbyt rozwijające powtarzanie tych samych czynności. Testy wykonują się w sposób automatyczny, a testerzy odpowiadają za kompletność repozytorium testów oraz jego poszerzanie o pojawiające się w aplikacji nowe funkcje oraz błędy zgłaszane przez klientów.
Wdrożenie automatycznych testów GUI jako uzupełnienie testów jednostkowych oraz testów komponentów wymiernie skróciło czas weryfikacji poprawności aplikacji przed wydaniem, przyspieszyło wydawanie kolejnych wersji oraz zmniejszyło ilość błędów w produkcie (szczególnie tzw. błędów powracających, czyli poprawionych w przeszłości i ponownie pojawiających się w nowych wydaniach). Squish nie jest oprogramowaniem bezpłatnym, poniesione nakłady zwracają się jednak szybko, a stosunek ceny do jakości powinien być zadowalający nawet dla wymagającego klienta.


Regulamin korzystania z portalu