fbpx

Testowanie przy użyciu JSoup

    Problem

    W przypadku aplikacji webowych czasem musimy zautomatyzować testy funkcjonalności, która nie wymaga dynamicznej symulacji działań użytkownika, ale na przykład statycznej weryfikacji części wyrenderowanego przez nasz backend kodu HTML. Przykładem mogą być wartości w znacznikach <meta>, zawierające kluczowe informacje, wykorzystywane przez zewnętrzne serwisy konsumujące treści z naszej platformy.

    Często pierwszym pomysłem w takim wypadku jest użycie Selenium do otwarcia strony i odczytanie jej źródła. Niesie to za sobą bardzo duży i niepotrzebny narzut w postaci konfiguracji środowiska, konieczności otwarcia przeglądarki, czekania na wyrenderowanie się strony itd. Parsowanie całego źródła strony w postaci tekstowej może być również nie lada wyzwaniem. Idealnie, gdybyśmy mogli szybko znaleźć wybrany element w markupie strony używając znanych nam narzędzi, jak na przykład… selektory CSS!

    Całe szczęście, ktoś już wpadł na ten pomysł i mamy do naszej dyspozycji gotowe narzędzie – JSoup.

    O JSoupie słów kilka

    JSoup jest open-sourceową biblioteką do scrapeowania i parsowania stron internetowych. Dostarcza bardzo przejrzyste API i pozwala na szybkie przeszukiwanie treści bez odpalania przeglądarki.

    Ważne: JSoup jest biblioteką do pracy z HTML, nie silnikiem przeglądarki – nie będzie w stanie odczytać fragmentów strony renderowanych dynamicznie za pomocą Javascriptu po stronie przeglądarki.

    Do nawigowania po elementach markupu możemy użyć:

    Aby w naszym projekcie skorzystać z JSoup, wystarczy do niego dorzucić jedną zależność.

    • Maven:
    <dependency>
      <groupId>org.jsoup</groupId>
      <artifactId>jsoup</artifactId>
      <version>1.12.1</version>
    </dependency>
    • Gradle:
    compile 'org.jsoup:jsoup:1.12.1

    Zobaczmy na przykładzie jak wygląda używanie JSoup w praktyce.

    Testy tagów Open Graph i Twitter Cards

    Za nasz cel obierzemy sobie następującą stronę: https://css-tricks.com/essential-meta-tags-social-media/ (przy okazji, polecamy również samą treść artykułu :)). Jak tytuł sugeruje – napiszemy test weryfikujący meta tagi wpływające na to, jak wyświetla się treść naszej strony na mediach społecznościowych.

    Podglądając źródło strony, widzimy interesujący nas fragment:

    <meta property="og:locale" content="en_US" />
    <meta property="og:type" content="article" />
    <meta property="og:title" content="The Essential Meta Tags for Social Media | CSS-Tricks" />
    <meta property="og:description" content="These days, almost every website encourages visitors to share its pages on social media. We’ve all seen the ubiquitous Facebook and Twitter icons, among" />
    <meta property="og:url" content="https://css-tricks.com/essential-meta-tags-social-media/" />
    <meta property="og:site_name" content="CSS-Tricks" />
    <meta property="article:publisher" content="https://www.facebook.com/CSSTricks" />
    <meta property="article:section" content="Article" />
    <meta property="article:published_time" content="2016-06-20T13:18:32+00:00" />
    <meta property="article:modified_time" content="2016-12-21T18:43:43+00:00" />
    <meta property="og:updated_time" content="2016-12-21T18:43:43+00:00" />
    <meta property="og:image" content="//css-tricks.com/wp-content/uploads/2016/06/facebook-card.jpg" />
    <meta name="twitter:card" content="summary" />
    <meta name="twitter:description" content="These days, almost every website encourages visitors to share its pages on social media. We’ve all seen the ubiquitous Facebook and Twitter icons, among" />
    <meta name="twitter:title" content="The Essential Meta Tags for Social Media | CSS-Tricks" />
    <meta name="twitter:site" content="@CSS" />
    <meta name="twitter:image" content="//css-tricks.com/wp-content/uploads/2016/06/facebook-card.jpg" />
    <meta name="twitter:creator" content="@adamcoti" />

    Znajdują się tutaj zarówno tagi Open Graph (https://ogp.me/) oraz specyficzne dla Twittera (https://developer.twitter.com/en/docs/tweets/optimize-with-cards/overview/markup.html).

    Napiszmy test sprawdzający czy tytuł wyrenderowany w tych tagach, odpowiada naszym oczekiwaniom.

    Najpierw musimy pozyskać źródło naszej strony:

    Document doc = Jsoup.connect("https://css-tricks.com/essential-meta-tags-social-media/").get();

    Następnie, z uzyskanego obiektu musimy wyciągnąć interesujące nas meta tagi, czyli og:title oraz twitter:title, a potem wartość atrybutu content:

    String ogTitle = doc.selectFirst("meta[property='og:title']").attr("content");
    String twitterTitle = doc.selectFirst("meta[name='twitter:title']").attr("content");

    W kolejnym kroku, pozostaje nam zweryfikowanie czy odczytane tytuły odpowiadają temu oczekiwanemu:

    assertAll("Asserting titles in meta tags",        
        () -> assertEquals(expectedTitle, ogTitle, "Title did not match the expected one in og:title tag"),
        () -> assertEquals(expectedTitle, twitterTitle, "Title did not match the expected one in twitter:title tag"));

    Alternatywnie, wykorzystując możliwości selektorów CSS oraz oferowanego przez JSoup API, znaleźć wszystkie elementy zawierające :title w swoich atrybutach:

    Elements titleTags = doc.select("meta[name*=':title'],meta[property*=':title']");

    I następnie, dla każdego z nich dokonać asercji:

    titleTags.forEach(tag -> assertEquals(expectedTitle, tag.attr("content"), "Title did not match the expected one in the tag: " + tag.attr("name")));

    I… to wszystko! Cały test zajmuje kilka linijek oraz trwa poniżej sekundy – znacząco szybciej i prościej niż zaprzęganie do tego zadania Selenium :).

    Coś więcej?

    API JSoupa jest naturalnie o wiele bogatsze – zachęcamy do eksploracji i zabawy tą biblioteką na własną rękę. 

    Dodatkowo, możemy pokusić się o zaimplementowanie czegoś podobnego do podejścia Page Object, gdzie modelujemy poszczególne fragmenty strony, a pod spodem wyszukujemy odpowiednie elementy przy pomocy JSoupa – hm, czyżby pomysł na kolejny post… :)?

    Przy testach na większą skalę można również pokusić się o małą optymalizację w postaci wprowadzenia wzorca Flyweight przy pobieraniu źródła dla danego URLa – w ten sposób ograniczymy ilość zapytań do serwera.

    Podsumowanie

    Mamy nadzieję, że zaprezentowany powyżej JSoup pomoże Wam w testach statycznych elementów Waszych stron! Jak widzicie na powyższych przykładach, bardzo szybko możemy zweryfikować całkiem sporo rzeczy trawersując HTML naszej strony przy pomocy łatwo weryfikowalnych CSS selektorów.

    Przykłady funkcjonalności, które można sprawdzić przy pomocy zbadania HTML strony można mnożyć. Poniżej niektóre, które mieliśmy okazję weryfikować przy użyciu JSoupa:

    • poprawność wyrenderowanych wspomnianych wyżej meta tagów związanych z mediami społecznościowymi
    • poprawność zawartości Structured Data (https://developers.google.com/search/docs/guides/intro-structured-data)
    • statyczne sekcje stron, ale dynamicznie generowane, np. listujące posty, produkty itd.
    • renderowanie się konfiguracji serwisów zewnętrznych jaka np. snippety związane z Google Analytics
    • renderowanie w treści strony tagów kontrolujących działanie zintegrowanych zewnętrznych silników wyszukiwania
    • weryfikacja poprawności routingu w systemie przez szybkie sprawdzanie elementów w markupie (np. obecność linku do pliku CSS z danej części systemu)

    A Wy jakie przykłady zastosowania widzicie w Waszych aplikacjach?


    Kod jak zawsze dostępny jest na GitHubie: https://github.com/devowlsgithub/testing-with-jsoup


    Cover: Photo by Henrique Félix on Unsplash

      About Michał Krzyżanowski

      Dodaj komentarz