aA

Statyczne testy interfejsu graficznego przy użyciu JUnit, Selenium i AShot na przykładzie EuroAP

Statyczne testy interfejsu graficznego przy uzyciu junit selenium i ashot na przykladzie euroap

Nieodłącznym elementem wytwarzania oprogramowania jest jego testowanie. Testy pozwalają zadbać o wysoką jakość tworzonych aplikacji oraz zaoszczędzić sporą ilość czasu. Poza testowaniem manualnym, pewne procesy można zautomatyzować. Dlatego dzisiaj napiszemy o tym, jak przetestować interfejs aplikacji webowej na przykładzie EuroAP przy użyciu Javy oraz bibliotek JUnit, Selenium i AShot.

Wyróżniamy wiele rodzajów testów, a każde z nich mają za zadanie sprawdzić naszą aplikację pod nieco innym kątem.

Jaki cel mają omawiane testy?

EuroAP to serwer aplikacji zbudowany w oparciu o kod źródłowy JBoss® EAP, który służy do uruchamiania aplikacji Java i zarządzania nimi oraz wiele innych. Posiada on interfejs graficzny, dzięki któremu możemy zarządzać całą infrastrukturą – i to on będzie celem naszych testów.

Przejdziemy dziś przez przykładowy scenariusz testowy przy użyciu Selenium – tak, jakby po konsoli webowej poruszał się użytkownik – i sprawdzimy, czy poszczególne elementy interfejsu graficznego:

  • wyglądają tak, jak tego oczekujemy
  • znajdują się w odpowiednich miejscach
  • wywołują żądany efekt po kliknięciu ich.

Przeprowadzenie takiego scenariusza testowego umożliwia nam Selenium. Biblioteka ta pozwala uruchomić przeglądarkę internetową oraz wykonać pewne czynności, imitując zachowanie użytkownika. Daje również możliwość lokalizowania elementów webowych, klikania ich oraz pobierania informacji o nich.

Sposób testowania oraz wykorzystania technologii JUnit, Selenium i AShot

Od EuroAP wymagamy zawsze tego samego – konkretnego wyglądu oraz układu w konsoli webowej. Dlatego strategią, jaką przyjęliśmy, jest wykonywanie zrzutów konsoli webowej w trakcie działania Selenium oraz porównywanie ich z wcześniej przygotowanymi zrzutami tejże konsoli. W ten sposób sprawdzamy wygląd konsoli, jej branding, zachowanie oraz ogólne funkcjonowanie interfejsu graficznego.

Myślę, że działanie oraz zamysł testów najlepiej zobrazuje nam przedstawienie jego flow wraz z krótkim opisem poszczególnych etapów.

Flow testów, trochę screenów oraz kodu

Tool testujący jest napisany w Javie, dlatego możemy go uruchomić w prosty sposób:

java -jar visual-tests-tool.jar EuroAP

Omawiany tool testujący działa również z produktem EuroSSO. Jednak w związku z tym, że skupiamy się na testach serwera aplikacji EuroAP, w powyższym wywołaniu jako parametr podałem „EuroAP”. Aby nasza aplikacja testowa została poprawnie uruchomiona, musi znajdować się w tej samej lokalizacji co testowany serwer aplikacji.
Przejdźmy do flow testowego.

  1. W pierwszej kolejności uruchamiamy EuroAP. Robimy to za pomocą komendy bashowej, którą wywołuje visual-tests-tool:
...
    ProcessBuilder pb = new ProcessBuilder("./Console/bin/standalone.sh");
    try {
        pb.start();
    } catch (IOException e) {
        e.printStackTrace();
    }
...

2. Następnie do akcji wkracza Selenium. Tworzymy obiekt ChromeDriver, który pozwoli nam uruchomić przeglądarkę Google Chrome. Dzięki niej nasza aplikacja będzie mogła swobodnie poruszać się po interfejsie graficznym. Używamy konkretnej puli opcji (ChromeOptions). Kluczowym parametrem w tym wypadku jest "--windows-size=1920,1200", który pozwala uruchamiać przeglądarkę zawsze w tej samej rozdzielczości, co umożliwia porównywanie tworzonych screenów.

W następnej kolejności inicjalizujemy uruchomienie przeglądarki wraz z adresem, pod którym uruchomiona jest nasza konsola webowa:

        final String URL = "http://127.0.0.1:9090/";
        ChromeOptions chromeOptions = new ChromeOptions();
        chromeOptions.addArguments("--no-sandbox", "--headless", "--window-size=1920,1200", "--ignore-certificate-errors", "--disable-extensions");
        WebDriver driver = new ChromeDriver(chromeOptions);
        ((HasAuthentication) driver).register(UsernameAndPassword.of("test", "test"));
        driver.get(URL);

Naszym oczom ukazuje się ekran powitalny konsoli EuroAP:

EuroAP

 

Zanim przejdziemy dalej – w powyższym kodzie widnieje jeszcze linijka:

((HasAuthentication) driver).register(UsernameAndPassword.of("test", "test"));

Jest ona odpowiedzialna za przekazanie loginu i hasła do Pop-upu przeglądarki (HTTP Authentication), który pozwala nam uzyskać dostęp do konsoli EuroAP.

Dwie ciekawostki z tym związane:

  • przez zmiany wprowadzone do Google Chrome, przy użyciu Selenium w wersji starszej niż 4.0.0, mogą pojawić się problemy z obsłużeniem takiego PopUpu
  • co najmniej do wersji 4.0.0-beta-1 w Selenium jest błąd, przez który do PopUpu możemy zalogować się tylko, jeżeli login oraz hasło są takie same, ponieważ do uzupełnienia loginu i hasła zawsze używa pierwszego parametru.

Dla przykładu, jeżeli próbowalibyśmy się zalogować loginem: euroapLogin oraz hasłem euroapPass:

((HasAuthentication) driver).register(UsernameAndPassword.of("euroapLogin", "euroapPass"));

to Selenium do Pop-upu i tak przekazuje login: euroapLogin i hasło: euroapLogin.

3. Po poprawnym uruchomieniu strony wykonujemy zrzut ekranu przeglądarki. Następnie wczytujemy odpowiedni screen z oczekiwanym wyglądem konsoli do zmiennej:

expectedScreen oraz za pomocą ->imageDiffer.makeDiff(screen, expectedScreen).hasDiff() sprawdzamy, czy zrzuty różnią się między sobą:

        final String imageName = "main_page.png";
        ImageDiffer imageDiffer = new ImageDiffer();

        Screenshot screen = new AShot()
                .shootingStrategy(ShootingStrategies.simple())
                .takeScreenshot(driver);

        Screenshot expectedScreen = CommonUtils.getExpectedScreenshot(screen, PATH, imageName);
        assertFalse(imageDiffer.makeDiff(screen, expectedScreen).hasDiff());

Zarówno obiekt ImageDiffer, jak i Screenshot pochodzą z biblioteki AShot.

4. Punkty 2 i 3 możemy powtarzać w dowolnej ilości, dostosowując je do konkretnych przypadków testowych, które chcemy przeprowadzić.

Przykładowo, klikając w EuroAP w wersję w prawym dolnym rogu, wyświetli nam się PopUp z informacjami dotyczącymi konsoli. Oczywiście możemy to „wyklikać” za pomocą Selenium:

        Optional<WebElement> clickableVersion = driver.findElements(By.tagName("span")).stream().filter(a -> a.getText().contains(".Final")).findFirst();
        clickableVersion.ifPresent(WebElement::click);

Oto rezultat:

EuroAP

Jeżeli z jakiegoś powodu chcemy ominąć konkretny obszar widoczny na zrzucie ekranu, możemy to uwzględnić podczas robienia screenu. Dla lepszego zrozumienia załóżmy, że z powyższego zrzutu chcemy wykluczyć obszar, w którym występuje Product Version, ponieważ wersja produktu może się zmienić, co niekoniecznie musi oznaczać błąd. Możemy to zrobić w następujący sposób:

        final Coords productVersionArea = new Coords(921, 163, 258, 40);
        final String imageName = "console_inf_pop_up.png";

        Optional<WebElement> clickableVersion = driver.findElements(By.tagName("span")).stream().filter(a -> a.getText().contains(".Final")).findFirst();
        clickableVersion.ifPresent(WebElement::click);

        Screenshot screen = new AShot()
                .shootingStrategy(ShootingStrategies.simple())
                .addIgnoredArea(productVersionArea)
                .takeScreenshot(driver);

        Screenshot expectedScreen = CommonUtils.getExpectedScreenshot(screen, PATH, imageName);
        assertFalse(imageDiffer.makeDiff(screen, expectedScreen).hasDiff());

Jak widać, podczas tworzenia zrzutu ekranu, skorzystaliśmy z metody .addIgnoredArea(productVersionArea). Dzięki temu, jeżeli w testowanej konsoli będzie widnieć inna wersja niż ta, która jest na oczekiwanych screenach, testy zakończą się poprawnie.

Uruchamianie testów JUnit jako aplikacja Javy

Wszystkie klasy testowe mają podobną strukturę i są napisane z użyciem adnotacji JUnit.

public class ApConsole {
    ...

    @BeforeAll
    static void beforeAll() {
        ...
    }

    @BeforeEach
    void beforeEach() {
        ...
    }

    @AfterEach
    void afterEach() {
        ...
    }

    @Test
    void checkMainPage() throws IOException {
        ...
    }

    ...

}

Za pomocą biblioteki junit-jupiter-engine możemy uruchomić wybrane klasy testowe napisane w JUnicie, a następnie w dowolny sposób zarządzać wynikami testów. Poniżej umieszczam fragment kodu, za pomocą którego uruchamiamy wybrane klasy zawierające testy. Następnie wyniki zapisujemy do zmiennej:

    LauncherDiscoveryRequest request = buildRequest();
    Launcher launcher = LauncherFactory.create();
    request = LauncherDiscoveryRequestBuilder.request()
                .selectors(selectClass(ApConsole.class))
                .selectors(selectClass(WelcomePages.class))
                .selectors(selectClass(Rebranding.class))
                .build();

    TestPlan testPlan = launcher.discover(request);
    SummaryGeneratingListener listener = new SummaryGeneratingListener();
    launcher.registerTestExecutionListeners(listener);
    launcher.execute(request);

    testExecutionSummary = listener.getSummary();

Rezultaty testów umieszczamy w zmiennej testExecutionSummary i możemy dowolnie nimi zarządzać. Znajdują się tam między innymi wyniki testów, dzięki którym możemy podejrzeć, które z nich zakończyły się niepowodzeniem (o ile takie są), co powinno znacznie ułatwić nam zlokalizowanie ewentualnego błędu aplikacji oraz jego przyczynę.

Podsumowanie

Selenium, JUnit oraz AShot mają ogrom możliwości, które mogą pomóc w testowaniu naszych aplikacji webowych. Powyżej znajduje się tylko zalążek oraz krótkie zobrazowanie, jak mogą one ze sobą współpracować podczas testowania interfejsu aplikacji. Temat testowania będziemy kontynuować w kolejnych częściach tego poradnika.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *