Michał Niedźwiecki

Michał Niedźwiecki Programista,
rozwiązuję problemy

Temat: Selenium RC i wgrywanie pre-conditions testów

Witam,

Rozwijamy projekt w Vaadin i do testów funkcjonalnych wykorzystujemy Selenium w wersji 2.

Testy funkcjonalne zautomatyzowaliśmy w taki sposób:
JUnit <-> Selenium <-> przeglądarka

Tj. w klasach JUnit zamieściliśmy instrukcje, które sterują Selenium. A Selenium wykonuje to na przeglądarce, która z kolei "przeklikuje" interface normalnie uruchomionej naszej aplikacji (po prostu działa na żywym systemie tak jak by to robił użytkownik).

Problem jest taki, że testy mają swoje pre-condition, czyli co musi być spełnione najpierw, żeby ten test mógł się wykonać. Np.:

Test X - sprawdzić czy strona po ustawieniu jej w panelu administracyjnym opcji "publiczny" jest dostępna dla wszystkich, a po ustawieniu opcji "prywatny" nie jest dostępna.
pre-condition 1: ta strona musi być najpierw stworzona.

Nasza aplikacja, którą testujemy i testy JUnit sterujące Selenium to są osobne procesy, które docelowo będą chodzić na osobnych hostach. Zatem nie możemy w prosty sposób z pominięciem interface zapewnić takie pre-condition np. przez wgranie persystancji z testowej bazy danych, tak jak to się robi np. w testach jednostkowych.

W tej chwili problem rozwiązujemy tak, że najpierw wykonywany jest test dodający tą stronę. Potem właściwy test X (który opisałem wyżej). Następnie test usuwający stronę (post-condition). Oczywiście spowalnia to proces wykonania się wszystkich testów, bo wprowadzenie pre-condition przez interface jest o rzędy wielkości dłuższe niż wgranie bezpośrednio do bazy danych.

Jak Wy rozwiązujecie tego typu problemy?

Rozważamy implementację interface JMX, który wprowadzi te pre-conditions i post-conditions szybciej. Ale może są jakieś gotowe rozwiązania? Persystencję w aplikacji zapewnia JPA. W zasadzie wszystko sprowadza się do wprowadzenia zmian w bazie danych i odświeżenia JPA. Jednak w naszym projekcie jest kładziony duży nacisk na nierobienie back-door'ów.Michał Niedźwiecki edytował(a) ten post dnia 06.02.13 o godzinie 07:53
Marcin Z.

Marcin Z. “Testing is an
infinite process of
comparing the
invisibl...

Temat: Selenium RC i wgrywanie pre-conditions testów

Hej!

Oczywiście przy założeniu, że nie znam detali systemu który musisz testować to w zależności od możliwości implementacji może zadziałać któraś z opcji:
a) wstrzykiwanie danych bezpośrednio do DB (różnie może być z zależnościami - referencje, etc.).
Można to robić w setupie testu. Najlepiej opakować w jakąś dołączaną klasę/bibliotekę.
+ masz bardzo elastyczne narzędzie
- może być to trudne w niektórych wypadkach trzeba się liczyć z utrzymaniem tego podobnie jak testu.

b) Obecnie zastosowane przez Was rozwiązanie. Koszt utrzymania zapewne większy niż w wypadku opcji A, zresztą sam pewnie znasz to doskonale:)

c) Zamiast wyklikiwać zmiany za pomocą selenium, może da się przechwycić samą końcówkę czyli wysłanie (HTTP GET/POST), a następnie je spreparować i odpalać przed każdym testem. Odpada grzebanie w DB i nie musisz wprowadzać zmian w AUT, ani utrzymywać tyle kodu Selenium co w opcji B.

d) Stworzyć interfejsy w aplikacji do wprowadzania takich zmian. Np. dostępne tylko w wersji DEBUG, na środowisku testowym czy dostępne z pewnej puli adresów IP, czy jeszcze inaczej zablokowane. Minusami tutaj są ingerencja w AUT oraz czas potrzebny na stworzenie odpowiednich mechanizmów w AUT.

Pewnie jest jeszcze parę opcji. Wszystkie mogą mieć zastosowanie, a nawet się sprawdzić:) Jak zwykle to zależy od sytuacji.

Pozdrawiam!Marcin Złotowicz edytował(a) ten post dnia 31.01.13 o godzinie 19:34
Piotr D.

Piotr D. Tester
Oprogramowania

Temat: Selenium RC i wgrywanie pre-conditions testów

Michał Niedźwiecki:
Problem jest taki, że testy mają swoje pre-condition, czyli co musi być spełnione najpierw, żeby ten test mógł się wykonać.

... :) co stoi dokładnie w poprzek stosowaniu frameworka do testów _jednostkowych_ do automatyzacji innego rodzaju testów. Klasyczny uruchamiany przez programistę unit test jeżeli potrzebuje warunków wstepnych innych niż może sobie ustawić sam lub jego wynik zależy od kolejności wykonania, to najprawdopodobniej jest wadliwy by design
W przypadku testów "w warstwie widoku" możliwości ja widzę dwie:
[1] pozbyć się frameworka do testów jednostkowych całkowicie i zastąpić rozwiązaniem opartym o jakiś mechanizm workflow-ów (bo tak testy zazwyczaj są logicznie ułożone, szczególnie integracyjne) - coś jak Windows Workflow, może Quartz(?) (dla Javy).
[2] oddelegować zarządanie kolejnością i decyzją do uruchomienia testów ponad framework do testów jednostkowych, który będzie służył tylko do uruchamiania pojedyczych testów i produkcji później agregowanych raportów.

Nie rozwiązuje to do końca problemu który zdefiniowałeś (moim zdaniem, to nie problem - tylko naturalna konsekwencja stanu rzeczy, na którą po prostu rzuciliśmy sprzęt + pomyślunek ) natomiast umożliwia podejście w którym dobrze podzielony pomiędzy scenariusze zakres odpowiedzialności niweluje kłopot z tego wymagania praktycznie do zera. Wtedy łańcuchy zależności są krotkie, więc można je zrównoleglić - a wtedy ograniczeniem jest tylko dostępna infrastruktura.

Obecnie wykorzystuję podejście 2: test jest opisany w TestLinku, gdzie jest dodatkowo informacja o lokalizacji automatu który go wykonuje (nazwie testu w NUnitcie).Dedykowane narzędzie uruchamiane przez serwer CI wg. podanych parametrów wyciąga odpowiedni testplan, waliduje konfigurację, ustawia kolejność wykonania zadań (tu jest kilka wariantów) nastepnie wystepuje o przydział maszyn zdolnych do wykonania testu (na podstawie opisu testu z TP) we wskazanych wariantach,
konfiguruje je i wywołuje w tym przypadku NUnita.
Test na podstawie konfiguracji wrzuconej przez narzedzie (z test planu), sam sobie dociąga za pomocą dedykowanej biblioteki konfigurację wskazanego dla konkretnego wykonania środowiska testowego, aktualny zestaw i pozycję rekordu danych testowych oraz miejsce gdzie ma wyrzucić artefakty (każdorazowo skonfigurowane przez wspomniane narzędzie). Gdy skończy, maszyna wraca do puli i czeka na nastepny przydział. Założenie - narazie sztywne - jest takie, że testy w obrębie testsuite'a sa wykonywane w zdefiniowanej ręcznie w TP kolejności, poza TS-ami sa niezależne.Idea jest taka, że test kiedy się "budzi" na maszynie, ma podłożoną pod nos całą konfigurację do bieżącego wykonania i zakłada że skoro "wstał" tzn. że może działać. Oczywiście, nie przeszkadza to w oczekiwaniu na warunek (pojawienie się np. rekrodu w bazie, wiadomości w kolejce itp.).
Na koniec wykonania takiej build konfiguracji skrypt zbiera raport, podrzuca to serwerowi CI do parsowania (TeamCity) oraz odpowiada za zwolnienie maszyn, gdyby zdarzyło się że nadzorca padł z losowych przyczyn.
W drodze jest funkcjonalność "checkpointing-u" (zatrzymania test planu po padzie wybranych testów) oraz odtwarzania środowiska do stanu sprzed jego uruchomienia.

Przy czym, tak długo jak znamy warunki początkowe dla wybranego testu, to możemy je wcześniej albo wprowadzić innym testem "właściwym" w sposób zgodny z przypadkiem użycia, albo nadal w tej samej konwencji - wywołać "test", właściwie zaślepke, która tam gdzie potrzeba w całym systemie umieści odpowiednie rzeczy. Z różnych przyczyn - o czym dalej - tego staramy się unikać.
Warunkiem do tego podejścia z "testami zaślepkami" jest też dobre oprogramowanie - i wyprowadzenie poza testy usług realizujących ustawienie, weryfikację i usuwanie preconditions. Choćby ze względu na ułatwione utrzymanie testów i zarządzanie taką konfiguracją
Postconditions powinny poswstać automagicznie w wyniku wykonania testu.
Michał Niedźwiecki:
Nasza aplikacja, którą testujemy i testy JUnit sterujące Selesnium to są osobne procesy, które
docelowo będą chodzić na osobnych hostach.

Konfiguracja jak wyżej potrafi działać z tym samym testem, dla róznych środowisk docelowych, osobnymi danymi dla każdej instancji np. na 6 przeglądarkach jednoczesnie (i hostach, choć u nas "węzeł" tak naprawde jest to konto użytkownika, których na maszynie fizycznej czy wirtualnej może być naraz tyle, na ile licencja na RDP pozwala). Srodowisko z testowanym oprogramowaniem zmienia się jednym parametrem i ten sam test, z tymi samymi danymi, można puścić np. na dwa środowiska równolegle (na tylu przeglądarkach, na ile wolnych maszyn starczy; gdy braknie, to część zadań dokończy się gdy któraś się zwolni). Przy czym narzedzie sterujące całością i przydziałem maszyn, działa poza środowiskiem czy to maszyn na których działają testy czy też tego gdzie jest właściwy testowany produkt.

Alternatywnie, mogę na wycinku puli maszyn uruchomić ten sam test na tę samą platformę, z innym rekordem danych każdy - i wtedy "preconditions" mogę sobie (w zakresie ograniczeń logiki biznesowej) naładować na zapas.
Michał Niedźwiecki:
Zatem nie możemy w prosty sposób z pominięciem interface zapewnić takie pre-condition np.
przez wgranie persystancji z testowej bazy danych, tak jak to się robi np. w testach
jednostkowych.

Właściwie dlaczego się nie da ? Potrafię wskazać wiele powodów dla ktorych się nie powinno, ale dlaczego nie da ?
Michał Niedźwiecki:
W tej chwili problem rozwiązujemy tak, że najpierw wykonywany jest test dodający tą stronę. Potem właściwy test X (który opisałem wyżej). Następnie test usuwający stronę (post-condition). Oczywiście spowalnia to proces wykonania się wszystkich testów, bo wprowadzenie pre-condition przez interface jest o rzędy wielkości dłuższe niż wgranie bezpośrednio do bazy danych.

Wg. mnie na tym poziomie testów to jedyne słuszne rozwiązanie i wychodząc z niego, powstało podejście jak opisane wyżej. Testy jak te które opisałeś powyżej, to powinni robić programiści we własnym zakresie.
Jeżeli uważasz, że jest inaczej - to chętnie się dowiem, jak sobie radzisz w takim wypadku z zapewnieniem spójności danych i nazwijmy to, ciągłości przypadków użycia na środowisku ew. dlaczego uważasz to za nieistotne.
Michał Niedźwiecki:
Rozważamy implementację interface JMX, który wprowadzi te pre-conditions i post-conditions szybciej.

Poza tym - skoro i tak musisz / musicie zbudować funkcjonalność do preconditions... to po co robić coś nowego, dodatkowego ? Będzie to trzeba 1. stworzyć 2. utrzymywać 3. khm... ten...no....przetestować... używając właściwych testów do budowania środowiska po pierwsze koncentrujesz pracę na nich (z oczywistą korzyścią), po drugie siłą rzeczy zaczynasz je dzielić optymalniej, po trzecie ograniczasz "rozdęcie" całego oprzyrządowania testowego.Piotr D. edytował(a) ten post dnia 05.02.13 o godzinie 21:33



Wyślij zaproszenie do