Java >> Java Tutorial >  >> Java

Teilen von Code mit mehreren TestProject OpenSDK-Tests

Nachdem Sie einige Testmethoden geschrieben haben, die das TestProject OpenSDK verwenden, werden Sie wahrscheinlich bemerken, dass Ihr Test Methoden enthalten doppelten Code. Dieser Blogbeitrag beschreibt, wie Sie doppelten Code aus Ihrer Testsuite entfernen können.

Nachdem Sie diesen Blogbeitrag gelesen haben, werden Sie:

  • Verstehen Sie, warum Sie Testcode wiederverwenden sollten.
  • Wissen, was ein Seitenobjekt ist.
  • Kann Seitenobjekte erstellen.
  • Verstehen, wie Sie Seitenobjekte in Ihren Testklassen verwenden können, wenn Sie JUnit 5 verwenden.

Fangen wir an.

Warum sollten Sie Testcode wiederverwenden?

Wenn Sie Tests schreiben, die die Selenium-API verwenden, erstellen Sie eine Abhängigkeit zwischen Ihren Testklassen und der Implementierung des zu testenden Systems. Genauer gesagt erstellen Sie diese Abhängigkeit, wenn Sie HTML-Elemente auf einer HTML-Seite finden, indem Sie id-Attribute, Klassenattribute, Elementnamen, CSS-Selektoren usw. verwenden.

Um die Sache noch schlimmer zu machen, da es wahrscheinlich ist, dass mehrere Testklassen mit denselben HTML-Seiten (Anmeldeseite) interagieren oder die UI-Komponenten (Hauptnavigationsmenü) verwenden müssen, fügen Sie Ihrer Testsuite möglicherweise doppelten Code hinzu. Das ist eine schreckliche Idee, weil:

  • Ihre Tests sind schwer zu schreiben, da Sie jedes Mal denselben Code schreiben müssen, wenn Sie mit einer HTML-Seite oder einer Komponente interagieren möchten, die für mehrere Tests erforderlich ist.
  • Wenn Sie eine HTML-Seite oder eine allgemeine UI-Komponente ändern, müssen Sie möglicherweise jede Testklasse ändern, die mit der geänderten Seite oder Komponente interagiert. Mit anderen Worten, Ihre Tests sind schwer zu warten.

Außerdem ist es gut zu verstehen, dass Sie die Abhängigkeit zwischen Ihren Testklassen und der Implementierung des zu testenden Systems nicht beseitigen können, da Ihre Tests in der Lage sein müssen, mit dem zu testenden System zu interagieren und Informationen aus der gerenderten HTML-Seite zu extrahieren. Abgesehen davon können Sie Ihre Situation viel verbessern, indem Sie Seitenobjekte verwenden.

Als nächstes erfahren Sie, was ein Seitenobjekt ist.

Einführung in Seitenobjekte

Martin Fowler spezifiziert den Begriff Seitenobjekt wie folgt:

Ein Seitenobjekt umschließt eine HTML-Seite oder ein Fragment mit einer anwendungsspezifischen API, sodass Sie Seitenelemente bearbeiten können, ohne im HTML herumzuwühlen.

Mit anderen Worten, ein Seitenobjekt verbirgt die Struktur einer HTML-Seite oder eines HTML-Fragments vor Ihren Testmethoden und stellt Methoden bereit, die es Ihren Testmethoden ermöglichen, entweder mit der HTML-Seite zu interagieren oder Informationen von ihr zu finden.

Seitenobjekte helfen Ihnen aus diesen zwei Gründen, Tests zu schreiben, die einfach zu lesen, zu schreiben und zu warten sind:

  • Seitenobjekte helfen Ihnen, doppelten Code zu eliminieren, da Ihre Testsuite nur eine Stelle hat, die Kenntnis von der Struktur der spezifischen HTML-Seite oder des Seitenfragments hat. Dadurch lassen sich Ihre Tests einfacher schreiben und verwalten .
  • Wenn Sie den Methoden Ihrer Seitenobjekte anwendungsspezifische Namen geben, können Sie eine domänenspezifische Sprache für Ihre Tests erstellen. Dies macht Ihre Tests leichter lesbar .

Lassen Sie uns weitermachen und herausfinden, wie Sie gute Seitenobjekte schreiben können.

Gute Seitenobjekte schreiben

Wenn Sie gute Seitenobjekte schreiben wollen, müssen Sie diese drei Regeln befolgen:

Zuerst , sollten Sie nicht ein Seitenobjekt pro HTML-Seite erstellen. Stattdessen sollten Sie die HTML-Seite in Abschnitte unterteilen und pro Abschnitt ein Seitenobjekt erstellen. Zum Beispiel SearchPage Seitenobjekt könnte ein Seitenobjekt namens SearchForm enthalten .

Wenn Sie eine HTML-Seite in Seitenobjekte unterteilen, sollten Sie außerdem die Struktur der HTML-Seite so modellieren, dass sie für die Benutzer Ihrer Anwendung sinnvoll ist. Wenn Sie dieser Technik folgen, können Sie eine domänenspezifische Sprache für Ihre Tests erstellen. Auf diese Weise können Sie Tests schreiben, die das Wesentliche Ihrer Testfälle hervorheben.

Zweiter , sollten die Methoden eines Seitenobjekts entweder Datencontainerobjekte oder andere Seitenobjekte zurückgeben. Typischerweise hat ein Seitenobjekt drei Arten von Methoden:

  • Die Methoden, die Informationen von der aktuellen HTML-Seite finden, sollten entweder primitive Datentypen, Datencontainerobjekte oder Sammlungen zurückgeben, die primitive Datentypen oder Datencontainerobjekte enthalten.
  • Die Methoden, mit denen Sie auf andere Abschnitte der aktuellen HTML-Seite zugreifen können, sollten andere Seitenobjekte zurückgeben.
  • Die Methoden, die zu einer anderen HTML-Seite navigieren oder die aktuelle HTML-Seite neu laden, sollten ein neues Seitenobjekt zurückgeben, das die geladene HTML-Seite darstellt.

Wenn Sie diese Regel befolgen, können Sie von diesen zwei Vorteilen profitieren:

  • Meistens müssen Sie die Selenium-API Ihren Testklassen nicht zur Verfügung stellen. Das bedeutet, dass Sie Ihre Tests schreiben können, indem Sie die domänenspezifische Sprache verwenden, die durch Ihre Seitenobjekte definiert ist.
  • Wenn Sie den Navigationspfad eines Features ändern, können Sie einfach die Signatur der entsprechenden Methode ändern und sehen sofort, welche Testklassen von der Änderung betroffen sind (Hinweis:Diese Klassen werden nicht mehr kompiliert).

Dritter , sollten Seitenobjekte keine Zusicherungen enthalten. Wie Sie sich erinnern, sind Seitenobjekte dafür verantwortlich, eine domänenspezifische Sprache bereitzustellen, die es Ihnen ermöglicht, mit einer HTML-Seite zu interagieren und Informationen darauf zu finden.

Auf der anderen Seite helfen Ihnen Zusicherungen, die Bedingungen anzugeben, die wahr sein müssen, nachdem Ihre Testmethode ausgeführt wurde. Mit anderen Worten, Zusicherungen helfen Ihnen, die Geschäftsregeln Ihrer Anwendung zu spezifizieren, und deshalb denke ich, dass Sie Ihre Zusicherungen zu Ihren Testmethoden hinzufügen sollten.

Denken Sie daran, dass Sie, wenn Sie Ihren Seitenobjekten Zusicherungen hinzufügen, am Ende die Präsentationslogik mit der Geschäftslogik Ihrer Anwendung vermischen. Mit anderen Worten, Sie schreiben „aufgeblähte“ Seitenobjekte, die zu viele Verantwortlichkeiten haben.

Bevor Sie Ihre Seitenobjekte schreiben können, müssen Sie lernen, umgebungsspezifische Konfigurationen an Ihren Testcode zu übergeben. Als nächstes erfahren Sie, wie Sie dieses Problem lösen können.

Umgebungsspezifische Konfiguration an Ihren Testcode übergeben

Es ist wahrscheinlich, dass Sie Ihre Tests in verschiedenen Umgebungen ausführen müssen. Beispielsweise müssen Sie möglicherweise sicherstellen, dass das zu testende System wie erwartet funktioniert, wenn es in Ihrer lokalen Entwicklungsumgebung, Testumgebung oder Produktionsumgebung ausgeführt wird.

Das bedeutet, dass Sie in der Lage sein müssen, umgebungsspezifische Konfigurationen an Ihren Testcode zu übergeben. Beispielsweise müssen Sie in der Lage sein, die Basis-URL des zu testenden Systems zu konfigurieren. Wenn Sie die Basis-URL des zu testenden Systems an Ihren Testcode übergeben möchten, müssen Sie die folgenden Schritte ausführen:

Zuerst , müssen Sie einen final WebDriverEnvironment erstellen Klasse und stellen Sie sicher, dass Sie sie nicht instanziieren können. Diese Klasse stellt static bereit Methoden, mit denen Sie mithilfe von JVM-Systemeigenschaften auf umgebungsspezifische Konfigurationen zugreifen können, die an Ihre Tests übergeben werden.

Nachdem Sie diese Klasse erstellt haben, müssen Sie eine static getBaseUrl() schreiben Methode, indem Sie diesen Schritten folgen:

  1. Lesen Sie die Basis-URL des zu testenden Systems aus einer JVM-Systemeigenschaft namens webdriver.base.url .
  2. Wenn keine Basis-URL gefunden wird, werfen Sie einen neuen RuntimeException .
  3. Gib die gefundene Basis-URL zurück.

Nachdem Sie den WebDriverEnvironment geschrieben haben Klasse sieht der Quellcode wie folgt aus:

final class WebDriverEnvironment {

    private WebDriverEnvironment() {}
    
    static String getBaseUrl() {
        String baseUrl = System.getProperty("webdriver.base.url");
        if (baseUrl == null) {
            throw new RuntimeException("No base url found!");
        }
        return baseUrl;
    }
}

Zweiter , müssen Sie einen public erstellen und final Klasse namens WebDriverUrlBuilder und legen Sie diese Klasse in dasselbe Paket wie WebDriverEnvironment Klasse. Nachdem Sie diese Klasse erstellt haben, müssen Sie sicherstellen, dass Sie sie nicht instanziieren können.

Die WebDriverUrlBuilder Klasse stellt einen static bereit Factory-Methode, mit der Sie fest codierte URL-Adressen durch umgebungsspezifische URL-Adressen ersetzen können. Mit anderen Worten, diese Klasse hilft Ihnen, Tests zu schreiben, die in verschiedenen Umgebungen ausgeführt werden können.

Nachdem Sie den WebDriverUrlBuilder erstellt haben Klasse müssen Sie die erforderliche Factory-Methode schreiben, indem Sie diesen Schritten folgen:

  1. Fügen Sie static buildFromPath() hinzu Methode zum WebDriverUrlBuilder Klasse. Diese Methode nimmt die Pfadvorlage und die Parameter, die von den Formatbezeichnern referenziert werden, die aus dem Pfad String gefunden werden als Methodenparameter. Außerdem gibt diese Methode die erstellte URL-Adresse zurück.
  2. Wenn der Pfad null ist , werfen Sie einen neuen NullPointerException .
  3. Erstellen Sie den echten Pfad mit format() Methode des String Klasse.
  4. Rufen Sie die Basis-URL ab.
  5. Wenn die Basis-URL nicht mit dem Zeichen „/“ endet, hängen Sie das Zeichen „/“ an die Basis-URL an.
  6. Wenn der Pfad mit dem Zeichen '/' beginnt, ersetzen Sie dieses Zeichen durch eine leere Zeichenfolge.
  7. Hängen Sie den Pfad an die Basis-URL an und geben Sie die erstellte URL-Adresse zurück.

Nachdem Sie den WebDriverUrlBuilder geschrieben haben Klasse sieht der Quellcode wie folgt aus:

public final class WebDriverUrlBuilder {

    private WebDriverUrlBuilder() {}
    
    public static String buildFromPath(String path, Object... params) {
        if (path == null) {
            throw new NullPointerException("Path must be given.");
        }

        path = String.format(path, params);

        String baseUrl = WebDriverEnvironment.getBaseUrl();
        if (!baseUrl.endsWith("/")) {
            baseUrl += "/";
        }

        if (path.startsWith("/")) {
            path = path.replaceFirst("/", "");
        }

        return baseUrl + path;
    }
}

Dritter , müssen Sie den Wert von webdriver.base.url setzen Systemeigenschaft, indem Sie eine dieser drei Optionen verwenden:

Wenn Sie Ihre Tests mit Gradle ausführen, können Sie den Wert von webdriver.base.url festlegen Systemeigenschaft, indem Sie den folgenden Code zu Ihrer build.gradle hinzufügen Datei:

tasks.withType(Test) {
    systemProperty 'webdriver.base.url',
            System.getProperty('webdriver.base.url', 'https://www.petrikainulainen.net')
}

Wenn Sie Ihre Tests mit Maven ausführen, können Sie den Wert von webdriver.base.url festlegen Systemeigenschaft, indem Sie die folgende Plugin-Konfiguration verwenden:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.2</version>
    <configuration>
        <systemPropertyVariables>
            <webdriver.base.url>https://www.petrikainulainen.net</webdriver.base.url>
        </systemPropertyVariables>
    </configuration>
</plugin>

Wenn Sie Ihre Tests mit Ihrer IDE ausführen, können Sie den Wert von webdriver.base.url festlegen Systemeigenschaft, indem Sie das folgende Argument an die gestartete JVM übergeben:

-Dwebdriver.base.url=https://www.petrikainulainen.net .

Wenn Sie beispielsweise IntelliJ IDEA verwenden, können Sie dieses Argument an die gestartete JVM übergeben, indem Sie die folgende „Run Configuration“ verwenden:

Lassen Sie uns weitermachen und herausfinden, wie Sie Ihre Seitenobjekte schreiben können.

Schreiben Ihrer Seitenobjekte

Während dieses Blogbeitrags werden Sie die Tests korrigieren, die Sie geschrieben haben, als Sie lernten, Tests für Webanwendungen mit TestProject OpenSDK und JUnit 5 zu schreiben. Wenn Sie Ihre Tests korrigieren möchten, müssen Sie diese Seitenobjekte schreiben:

  • Der SearchPage Klasse ist ein Seitenobjekt, das es Ihnen ermöglicht, mit der Suchseite zu interagieren.
  • Der SearchResultPage ist ein Seitenobjekt, mit dem Sie Informationen auf der Suchergebnisseite finden können.

Außerdem müssen Sie eine Datencontainerklasse namens SearchResult schreiben . Diese Klasse enthält die Informationen eines einzelnen Suchergebnisses, das auf der Suchergebnisseite angezeigt wird.

Sie können diese Klassen schreiben, indem Sie diesen Schritten folgen:

Zuerst , müssen Sie den SearchResult schreiben Klasse. Diese Klasse hat einen private -Eigenschaft, die den Titel des Suchergebnisses enthält. Nachdem Sie den SearchResult geschrieben haben Klasse sieht der Quellcode wie folgt aus:

public class BlogPost {

    private final String title;

    public BlogPost(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }
}

Zweiter , müssen Sie den SearchResultPage erstellen Klasse und implementieren Sie sie, indem Sie diesen Schritten folgen:

  1. Fügen Sie einen final WebDriver hinzu Feld zur erstellten Klasse.
  2. Implementieren Sie einen package-private Konstruktor, der den Wert von webDriver festlegt -Feld mithilfe der Konstruktorinjektion.
  3. Schreiben Sie einen public Methode namens findNoSearchResultsText() . Diese Methode findet den Text, der auf der Suchergebnisseite angezeigt wird, wenn keine Suchergebnisse gefunden werden, und gibt den gefundenen Text zurück.
  4. Schreiben Sie einen public Methode namens findSearchResults() . Diese Methode findet die Suchergebnisse, die auf der Suchergebnisseite angezeigt werden, und gibt einen List zurück von BlogPost Objekte.

Nachdem Sie den SearchResultPage geschrieben haben Klasse sieht der Quellcode wie folgt aus:

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

import java.util.ArrayList;
import java.util.List;

public class SearchResultPage {

    private final WebDriver webDriver;

    SearchResultPage(WebDriver webDriver) {
        this.webDriver = webDriver;
    }
    
    public String findNoSearchResultsText() {
        WebElement noSearchResultsElement = webDriver.findElement(
                By.cssSelector(
                        ".template-search .content .post_box .archive_content"
                )
        );
        return noSearchResultsElement.getText();
    }
    
    public List<BlogPost> findSearchResults() {
        List<BlogPost> searchResults = new ArrayList<>();

        List<WebElement> searchResultElements = webDriver.findElements(
                By.tagName("article")
        );
        for (WebElement currentElement: searchResultElements) {
            WebElement searchResultTitle = currentElement.findElement(
                    By.className("headline")
            );
            BlogPost searchResult = new BlogPost(searchResultTitle.getText());
            searchResults.add(searchResult);
        }

        return searchResults;
    }
}

Dritter , müssen Sie den SearchPage erstellen Klasse und implementieren Sie sie, indem Sie diesen Schritten folgen:

  1. Fügen Sie einen final hinzu Feld namens pageUrl zur erstellten Klasse. Dieses Feld enthält die umgebungsspezifische URL der Suchseite.
  2. Fügen Sie einen final WebDriver hinzu Feld zur erstellten Klasse.
  3. Implementieren Sie einen Konstruktor, der den Wert von webDriver festlegt -Feld mithilfe der Konstruktorinjektion und erstellt die umgebungsspezifische URL der Suchseite.
  4. Schreiben Sie einen public Methode namens open() . Diese Methode öffnet die Suchseite und gibt einen neuen SearchPage zurück Objekt.
  5. Schreiben Sie einen public Methode namens findBlogPostsBySearchTerm() . Diese Methode nimmt den verwendeten Suchbegriff als Methodenparameter, gibt den Suchbegriff in das Suchformular ein und sendet das Suchformular. Nachdem diese Methode das Suchformular abgeschickt hat, gibt sie einen neuen SearchResultPage zurück Objekt.

Nachdem Sie den SearchPage geschrieben haben Klasse sieht der Quellcode wie folgt aus:

import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

public class SearchPage {

    private final String pageUrl;
    private final WebDriver webDriver;

    public SearchPage(WebDriver webDriver) {
        this.pageUrl = WebDriverUrlBuilder.buildFromPath("/blog/");
        this.webDriver = webDriver;
    }
    
    public SearchPage open() {
        webDriver.get(pageUrl);
        return new SearchPage(webDriver);
    }

    public SearchResultPage findBlogPostsBySearchTerm(String searchTerm) {
        WebElement searchField = webDriver.findElement(By.id("s"));
        searchField.sendKeys(searchTerm);
        searchField.sendKeys(Keys.ENTER);
        return new SearchResultPage(webDriver);
    }
}

Als nächstes müssen Sie die erforderlichen Änderungen an Ihrer Testklasse vornehmen.

Vornehmen der erforderlichen Änderungen an Ihrer Testklasse

Sie können die erforderlichen Änderungen an Ihrer Testklasse vornehmen, indem Sie diesen Schritten folgen:

Zuerst , müssen Sie einen searchPage hinzufügen Feld zu Ihrer Testklasse. Dieses Feld enthält einen Verweis auf einen SearchPage -Objekt, mit dem Sie mit der Suchseite interagieren können. Nachdem Sie den searchPage hinzugefügt haben Feld zu Ihrer Testklasse, sieht der Quellcode wie folgt aus:

import io.testproject.sdk.DriverBuilder;
import io.testproject.sdk.drivers.web.ChromeDriver;
import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeOptions;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

@DisplayName("Search blog posts")
class BlogSearchTest {

    private static ChromeDriver driver;
    private SearchPage searchPage;

    @BeforeAll
    static void configureTestProjectOpenSDK() {
        driver = new DriverBuilder<ChromeDriver>(new ChromeOptions())
                .withCapabilities(new ChromeOptions())
                .build(ChromeDriver.class);
    }

    @Nested
    @DisplayName("When no search results are found")
    class WhenNoSearchResultsAreFound {

        @Test
        @DisplayName("Should display an empty search result page when no search results are found")
        void shouldDisplayEmptySearchResultPage() {
            driver.get("https://www.petrikainulainen.net/blog/");

            WebElement searchField = driver.findElement(By.id("s"));
            searchField.sendKeys("noresults");
            searchField.sendKeys(Keys.ENTER);

            WebElement noResultElement = driver.findElement(
                    By.cssSelector(
                            ".template-search .content .post_box .archive_content"
                    )
            );
            assertThat(noResultElement.getText()).isEqualTo("No results found.");
        }
    }

    @Nested
    @DisplayName("When one search result is found")
    class WhenOneSearchResultIsFound {

        @Test
        @DisplayName("Should display search result page that has one search result when one search result is found")
        void shouldDisplaySearchResultPageWithOneSearchResult() {
            driver.get("https://www.petrikainulainen.net/blog/");

            WebElement searchField = driver.findElement(By.id("s"));
            searchField.sendKeys("oneresult");
            searchField.sendKeys(Keys.ENTER);

            List<WebElement> searchResults = driver.findElements(
                    By.tagName("article")
            );
            assertThat(searchResults).hasSize(1);
        }

        @Test
        @DisplayName("Should display search result page that has the correct search result when one search result is found")
        void shouldDisplaySearchResultPageWithCorrectSearchResult() {
            driver.get("https://www.petrikainulainen.net/blog/");

            WebElement searchField = driver.findElement(By.id("s"));
            searchField.sendKeys("oneresult");
            searchField.sendKeys(Keys.ENTER);

            WebElement searchResult = driver.findElement(
                    By.tagName("article")
            );
            WebElement resultTitle = searchResult.findElement(
                    By.className("headline")
            );
            assertThat(resultTitle.getText())
                    .isEqualTo("Java Testing Weekly 22 / 2018");
        }
    }

    @AfterAll
    static void shutdownTestProjectOpenSDK() {
        driver.quit();
    }
}

Zweiter müssen Sie eine Setup-Methode schreiben, die ausgeführt wird, bevor eine Testmethode ausgeführt wird. Diese Methode öffnet die Suchseite und speichert den zurückgegebenen SearchPage Objekt im searchPage aufstellen. Nachdem Sie die Setup-Methode geschrieben haben, sieht der Quellcode Ihrer Testklasse wie folgt aus:

import io.testproject.sdk.DriverBuilder;
import io.testproject.sdk.drivers.web.ChromeDriver;
import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeOptions;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

@DisplayName("Search blog posts")
class BlogSearchTest {

    private static ChromeDriver driver;
    private SearchPage searchPage;

    @BeforeAll
    static void configureTestProjectOpenSDK() {
        driver = new DriverBuilder<ChromeDriver>(new ChromeOptions())
                .withCapabilities(new ChromeOptions())
                .build(ChromeDriver.class);
    }

    @BeforeEach
    void openSearchPage() {
        searchPage = new SearchPage(driver).open();
    }

    @Nested
    @DisplayName("When no search results are found")
    class WhenNoSearchResultsAreFound {

        @Test
        @DisplayName("Should display an empty search result page when no search results are found")
        void shouldDisplayEmptySearchResultPage() {
            driver.get("https://www.petrikainulainen.net/blog/");

            WebElement searchField = driver.findElement(By.id("s"));
            searchField.sendKeys("noresults");
            searchField.sendKeys(Keys.ENTER);

            WebElement noResultElement = driver.findElement(
                    By.cssSelector(
                            ".template-search .content .post_box .archive_content"
                    )
            );
            assertThat(noResultElement.getText()).isEqualTo("No results found.");
        }
    }

    @Nested
    @DisplayName("When one search result is found")
    class WhenOneSearchResultIsFound {

        @Test
        @DisplayName("Should display search result page that has one search result when one search result is found")
        void shouldDisplaySearchResultPageWithOneSearchResult() {
            driver.get("https://www.petrikainulainen.net/blog/");

            WebElement searchField = driver.findElement(By.id("s"));
            searchField.sendKeys("oneresult");
            searchField.sendKeys(Keys.ENTER);

            List<WebElement> searchResults = driver.findElements(
                    By.tagName("article")
            );
            assertThat(searchResults).hasSize(1);
        }

        @Test
        @DisplayName("Should display search result page that has the correct search result when one search result is found")
        void shouldDisplaySearchResultPageWithCorrectSearchResult() {
            driver.get("https://www.petrikainulainen.net/blog/");

            WebElement searchField = driver.findElement(By.id("s"));
            searchField.sendKeys("oneresult");
            searchField.sendKeys(Keys.ENTER);

            WebElement searchResult = driver.findElement(
                    By.tagName("article")
            );
            WebElement resultTitle = searchResult.findElement(
                    By.className("headline")
            );
            assertThat(resultTitle.getText())
                    .isEqualTo("Java Testing Weekly 22 / 2018");
        }
    }

    @AfterAll
    static void shutdownTestProjectOpenSDK() {
        driver.quit();
    }
}

Dritter , müssen Sie die Testmethode korrigieren, die sicherstellt, dass die Suchfunktion wie erwartet funktioniert, wenn keine Suchergebnisse gefunden werden. Wenn Sie diese Testmethode korrigieren, müssen Sie sicherstellen, dass Ihre Testmethode Ihre neuen Seitenobjekte verwendet. Nachdem Sie die erforderlichen Änderungen an Ihrer Testklasse vorgenommen haben, sieht der Quellcode wie folgt aus:

import io.testproject.sdk.DriverBuilder;
import io.testproject.sdk.drivers.web.ChromeDriver;
import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeOptions;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

@DisplayName("Search blog posts")
class BlogSearchTest {

    private static ChromeDriver driver;
    private SearchPage searchPage;

    @BeforeAll
    static void configureTestProjectOpenSDK() {
        driver = new DriverBuilder<ChromeDriver>(new ChromeOptions())
                .withCapabilities(new ChromeOptions())
                .build(ChromeDriver.class);
    }

    @BeforeEach
    void openSearchPage() {
        searchPage = new SearchPage(driver).open();
    }

    @Nested
    @DisplayName("When no search results are found")
    class WhenNoSearchResultsAreFound {

        @Test
        @DisplayName("Should display an empty search result page when no search results are found")
        void shouldDisplayEmptySearchResultPage() {
            SearchResultPage searchResultPage = searchPage
                    .findBlogPostsBySearchTerm("noresults");

            String noSearchResultsText = searchResultPage
                    .findNoSearchResultsText();
            assertThat(noSearchResultsText).isEqualTo("No results found.");
        }
    }

    @Nested
    @DisplayName("When one search result is found")
    class WhenOneSearchResultIsFound {

        @Test
        @DisplayName("Should display search result page that has one search result when one search result is found")
        void shouldDisplaySearchResultPageWithOneSearchResult() {
            driver.get("https://www.petrikainulainen.net/blog/");

            WebElement searchField = driver.findElement(By.id("s"));
            searchField.sendKeys("oneresult");
            searchField.sendKeys(Keys.ENTER);

            List<WebElement> searchResults = driver.findElements(
                    By.tagName("article")
            );
            assertThat(searchResults).hasSize(1);
        }

        @Test
        @DisplayName("Should display search result page that has the correct search result when one search result is found")
        void shouldDisplaySearchResultPageWithCorrectSearchResult() {
            driver.get("https://www.petrikainulainen.net/blog/");

            WebElement searchField = driver.findElement(By.id("s"));
            searchField.sendKeys("oneresult");
            searchField.sendKeys(Keys.ENTER);

            WebElement searchResult = driver.findElement(
                    By.tagName("article")
            );
            WebElement resultTitle = searchResult.findElement(
                    By.className("headline")
            );
            assertThat(resultTitle.getText())
                    .isEqualTo("Java Testing Weekly 22 / 2018");
        }
    }

    @AfterAll
    static void shutdownTestProjectOpenSDK() {
        driver.quit();
    }
}

Vierter , müssen Sie die Testmethoden festlegen, die sicherstellen, dass das zu testende System wie erwartet funktioniert, wenn ein Suchergebnis gefunden wird. Wenn Sie diese Testmethoden korrigieren, müssen Sie sicherstellen, dass Ihre Testmethoden Ihre neuen Seitenobjekte verwenden. Nachdem Sie die erforderlichen Änderungen an Ihrer Testklasse vorgenommen haben, sieht der Quellcode wie folgt aus:

import io.testproject.sdk.DriverBuilder;
import io.testproject.sdk.drivers.web.ChromeDriver;
import org.junit.jupiter.api.*;
import org.openqa.selenium.chrome.ChromeOptions;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

@DisplayName("Search blog posts")
class BlogSearchTest2 {

    private static ChromeDriver driver;
    private SearchPage searchPage;

    @BeforeAll
    static void configureTestProjectOpenSDK() {
        driver = new DriverBuilder<ChromeDriver>(new ChromeOptions())
                .withCapabilities(new ChromeOptions())
                .build(ChromeDriver.class);
    }

    @BeforeEach
    void openSearchPage() {
        searchPage = new SearchPage(driver).open();
    }

    @Nested
    @DisplayName("When no search results are found")
    class WhenNoSearchResultsAreFound {

        @Test
        @DisplayName("Should display an empty search result page when no search results are found")
        void shouldDisplayEmptySearchResultPage() {
            SearchResultPage searchResultPage = searchPage
                    .findBlogPostsBySearchTerm("noresults");

            String noSearchResultsText = searchResultPage
                    .findNoSearchResultsText();
            assertThat(noSearchResultsText).isEqualTo("No results found.");
        }
    }

    @Nested
    @DisplayName("When one search result is found")
    class WhenOneSearchResultIsFound {

        @Test
        @DisplayName("Should display search result page that has one search result when one search result is found")
        void shouldDisplaySearchResultPageWithOneSearchResult() {
            SearchResultPage searchResultPage = searchPage
                    .findBlogPostsBySearchTerm("oneresult");

            List<BlogPost> searchResults = searchResultPage.findSearchResults();
            assertThat(searchResults).hasSize(1);
        }

        @Test
        @DisplayName("Should display search result page that has the correct search result when one search result is found")
        void shouldDisplaySearchResultPageWithCorrectSearchResult() {
            SearchResultPage searchResultPage = searchPage
                    .findBlogPostsBySearchTerm("oneresult");

            BlogPost searchResult = searchResultPage.findSearchResults().get(0);
            assertThat(searchResult.getTitle())
                    .isEqualTo("Java Testing Weekly 22 / 2018");
        }
    }

    @AfterAll
    static void shutdownTestProjectOpenSDK() {
        driver.quit();
    }
}

Sie verstehen, warum Sie doppelten Code aus Ihrer Testsuite entfernen sollten, Sie können gute Seitenobjekte schreiben und Sie wissen, wie Sie Testmethoden schreiben können, die Ihre Seitenobjekte verwenden. Fassen wir zusammen, was Sie aus diesem Blogbeitrag gelernt haben.

Zusammenfassung

Dieser Blogpost hat Ihnen sechs Dinge beigebracht:

  • Ein Seitenobjekt verbirgt die Struktur einer HTML-Seite oder eines HTML-Fragments vor Ihren Testmethoden und stellt Methoden bereit, die es Ihren Testmethoden ermöglichen, entweder mit der HTML-Seite zu interagieren oder Informationen von ihr zu finden.
  • Sie sollten doppelten Code aus Ihrer Testsuite entfernen, indem Sie Seitenobjekte verwenden, da Seitenobjekte Ihnen helfen, Tests zu schreiben, die einfach zu lesen, zu schreiben und zu warten sind.
  • Wenn Sie Seitenobjekte erstellen, die eine HTML-Seite darstellen, sollten Sie die HTML-Seite in Abschnitte unterteilen und ein Seitenobjekt pro Abschnitt erstellen.
  • Die Methoden eines Seitenobjekts sollten entweder Datencontainerobjekte oder andere Seitenobjekte zurückgeben.
  • Seitenobjekte sollten keine Behauptungen enthalten.
  • Sie können umgebungsspezifische Konfigurationen an Ihren Testcode übergeben, indem Sie JVM-Systemeigenschaften verwenden.

P.S. Sie können die Beispielanwendung dieses Blogbeitrags von Github erhalten.


Java-Tag