Automatisierung in Selenium: Seitenobjektmodell und Seitenfabrik

Veröffentlicht: 2022-03-11

Das Schreiben automatisierter Tests ist mehr als nur ein Luxus für jedes agile Softwareentwicklungsteam. Es ist eine Notwendigkeit und ein wesentliches Werkzeug, um Fehler in frühen Phasen von Softwareentwicklungszyklen schnell zu finden. Wenn sich eine neue Funktion noch in der Entwicklungsphase befindet, können Entwickler automatisierte Tests durchführen und sehen, wie andere Teile des Systems von diesen Änderungen betroffen sind. In diesem Artikel wird erläutert, wie Sie das automatisierte Testen mit dem Seitenobjektmodell in Selenium beschleunigen können.

Durch die Testautomatisierung ist es möglich, die Kosten für die Fehlerbehebung zu senken und den Prozess der Softwarequalitätssicherung (QA) insgesamt zu verbessern. Mit geeigneten Tests haben Entwickler die Möglichkeit, Fehler zu finden und zu beheben, noch bevor sie zur Qualitätssicherung gelangen. Die Testautomatisierung hilft uns außerdem, Testfälle und Funktionen zu automatisieren, die sich ständig zurückbilden. Auf diese Weise haben QAs mehr Zeit, andere Teile der Anwendung zu testen. Darüber hinaus trägt dies dazu bei, die Qualität des Produkts in Produktionsfreigaben sicherzustellen. Als Ergebnis erhalten wir effektiv stabilere Produkte und einen effizienteren QS-Prozess.

Die Selenium-Automatisierung vereinfacht die Testautomatisierung für Webanwendungen

Selenium vereinfacht die Testautomatisierung für Webanwendungen
Twittern

Obwohl das Schreiben automatisierter Tests für Entwickler und Ingenieure wie eine leichte Aufgabe erscheinen mag, besteht immer noch die Möglichkeit, dass in jedem agilen Prozess schlecht implementierte Tests und hohe Kosten für die Codewartung entstehen. Der Versuch, ständig Änderungen oder Funktionen in einem agilen Entwicklungsprojekt bereitzustellen, kann sich als kostspielig erweisen, wenn Tests erforderlich sind. Das Ändern eines Elements auf einer Webseite, auf das sich 20 Tests stützen, erfordert, dass man diese 20 Testroutinen durchläuft und jede aktualisiert, um sie an diese neu eingeführte Änderung anzupassen. Dies kann nicht nur sehr zeitaufwändig sein, sondern auch ein ernsthaft demotivierender Faktor, wenn es darum geht, automatisierte Tests frühzeitig zu implementieren.

Aber was wäre, wenn wir die Änderung nur an einer Stelle vornehmen könnten und jede relevante Testroutine sie verwenden könnte? In diesem Artikel werfen wir einen Blick auf automatisierte Tests in Selenium und wie wir Seitenobjektmodelle verwenden können, um wartbare und wiederverwendbare Testroutinen zu schreiben.

Seitenobjektmodell in Selenium

Das Seitenobjektmodell ist ein Objektentwurfsmuster in Selenium, bei dem Webseiten als Klassen dargestellt werden und die verschiedenen Elemente auf der Seite als Variablen in der Klasse definiert werden. Alle möglichen Benutzerinteraktionen können dann als Methoden auf der Klasse implementiert werden:

 clickLoginButton(); setCredentials(user_name,user_password);

Da gut benannte Methoden in Klassen leicht lesbar sind, ist dies eine elegante Möglichkeit, Testroutinen zu implementieren, die sowohl lesbar als auch in Zukunft einfacher zu warten oder zu aktualisieren sind. Zum Beispiel:

Um das Seitenobjektmodell zu unterstützen, verwenden wir Page Factory. Page Factory in Selenium ist eine Erweiterung von Page Object und kann auf verschiedene Arten verwendet werden. In diesem Fall werden wir Page Factory verwenden, um Webelemente zu initialisieren, die in Webseitenklassen oder Seitenobjekten definiert sind.

Webseitenklassen oder Seitenobjekte, die Webelemente enthalten, müssen mit Page Factory initialisiert werden, bevor die Webelementvariablen verwendet werden können. Dies kann einfach durch die Verwendung der Funktion initElements auf PageFactory erfolgen:

 LoginPage page = new LoginPage(driver); PageFactory.initElements(driver, page);

Oder noch einfacher:

 LoginPage page = PageFactory.intElements(driver,LoginPage.class)

Oder im Klassenkonstruktor der Webseite:

 public LoginPage(WebDriver driver) { this.driver = driver; PageFactory.initElements(driver, this); }

Page Factory initialisiert jede WebElement- Variable mit einem Verweis auf ein entsprechendes Element auf der eigentlichen Webseite basierend auf konfigurierten „Locators“. Dies geschieht durch die Verwendung von @FindBy- Anmerkungen. Mit dieser Anmerkung können wir eine Strategie zum Suchen des Elements zusammen mit den notwendigen Informationen zu seiner Identifizierung definieren:

 @FindBy(how=How.NAME, using="username") private WebElement user_name;

Jedes Mal, wenn eine Methode auf dieser WebElement- Variablen aufgerufen wird, findet der Treiber sie zuerst auf der aktuellen Seite und simuliert dann die Interaktion. Falls wir mit einer einfachen Seite arbeiten, wissen wir, dass wir das Element jedes Mal auf der Seite finden, wenn wir danach suchen, und wir wissen auch, dass wir schließlich von dieser Seite weg navigieren und nicht zu ihr zurückkehren, wir können zwischenspeichern das nachgeschlagene Feld mit einer anderen einfachen Anmerkung:

 @FindBy(how=How.NAME, using="username") @CacheLookup private WebElement user_name;

Diese gesamte Definition der WebElement-Variablen kann durch ihre viel kürzere Form ersetzt werden:

 @FindBy(name="username") private WebElement user_name;

Die Annotation @FindBy unterstützt eine Handvoll anderer Strategien, die die Dinge etwas einfacher machen:

 id, name, className, css, tagName, linkText, partialLinkText, xpath
 @FindBy() private WebElement user_name; @FindBy(name="passsword") private WebElement user_password; @FindBy(className="h3") private WebElement label; @FindBy(css=”#content”) private WebElement text;

Nach der Initialisierung können diese WebElement-Variablen dann verwendet werden, um mit den entsprechenden Elementen auf der Seite zu interagieren. Der folgende Code wird zum Beispiel:

 user_password.sendKeys(password);

… sendet die angegebene Folge von Tastenanschlägen an das Passwortfeld auf der Seite, und es ist äquivalent zu:

 driver.findElement(By.name(“user_password”)).sendKeys(password);

Im weiteren Verlauf werden Sie oft auf Situationen stoßen, in denen Sie eine Liste von Elementen auf einer Seite finden müssen, und dann ist @FindBys praktisch:

 @FindBys(@FindBy(css=”div[class='yt-lockup-tile yt-lockup-video']”))) private List<WebElement> videoElements;

Der obige Code findet alle div -Elemente mit zwei Klassennamen „yt-lockup-tile“ und „yt-lockup-video“. Wir können dies noch weiter vereinfachen, indem wir es durch Folgendes ersetzen:

 @FindBy(how=How.CSS,using="div[class='yt-lockup-tile yt-lockup-video']") private List<WebElement> videoElements;

Außerdem können Sie @FindAll mit mehreren @FindBy- Annotationen verwenden, um nach Elementen zu suchen, die mit einem der angegebenen Locators übereinstimmen:

 @FindAll({@FindBy(how=How.ID, using=”username”), @FindBy(className=”username-field”)}) private WebElement user_name;

Jetzt, da wir Webseiten als Java-Klassen darstellen und Page Factory verwenden können, um WebElement- Variablen einfach zu initialisieren, ist es an der Zeit, zu sehen, wie wir einfache Selenium-Tests mit dem Page Object-Muster und Page Factory schreiben können.

Einfaches Selenium-Testautomatisierungsprojekt in Java

Lassen Sie uns für unser Seitenobjektmodell-Tutorial die Entwickleranmeldung für Toptal automatisieren. Dazu müssen wir die folgenden Schritte automatisieren:

  • Besuchen Sie www.toptal.com

  • Klicken Sie auf die Schaltfläche „Als Entwickler bewerben“.

  • Überprüfen Sie auf der Portalseite zuerst, ob sie geöffnet ist

  • Klicken Sie auf die Schaltfläche „Toptal beitreten“.

  • Füllen Sie das Formular aus

  • Senden Sie das Formular ab, indem Sie auf die Schaltfläche „Toptal beitreten“ klicken

Einrichten eines Projekts

  • Laden Sie Java JDK herunter und installieren Sie es

  • Laden Sie InteliJ Idea herunter und installieren Sie es

  • Erstellen Sie ein neues Maven-Projekt

  • Verknüpfen Sie „Project SDK“ mit Ihrem JDK, z. B.: unter Windows „C:\Program Files\Java\jdkxxx“

  • Gruppen-ID und Artefakt-ID einrichten:

 <groupId>SeleniumTEST</groupId> <artifactId>Test</artifactId>
  • Fügen Sie die Abhängigkeiten Selenium und JUnit Maven in Ihrer Projekt-POM-Datei hinzu
 <dependencies> <!-- JUnit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <!-- Selenium --> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-firefox-driver</artifactId> <version>${selenium.version}</version> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-support</artifactId> <version>${selenium.version}</version> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>${selenium.version}</version> </dependency> </dependencies>

Ersetzen Sie die Selenium-Version und die JUnit-Version durch die neuesten Versionsnummern, die Sie finden, indem Sie bei Google und auf der Selenium-Website nach JUnit Maven suchen.

Wenn die automatische Erstellung aktiviert ist, sollten Abhängigkeiten zu diesem Zeitpunkt automatisch heruntergeladen werden. Wenn nicht, aktivieren Sie einfach Plugins > install > install:install unter dem Maven Projects-Panel auf der rechten Seite Ihrer IntelliJ Idea IDE.

IDE-Screenshot des Selen-Test-Tutorials

Nachdem das Projekt gebootet wurde, können wir mit der Erstellung unseres Testpakets unter „src/test/java“ beginnen. Benennen Sie das Paket „com.toptal“ und erstellen Sie zwei weitere Pakete darunter: „com.toptal.webpages“ und „com.toptal.tests“.

Screenshot des Selentest-Tutorials

Wir behalten unsere Page Object/Page Factory-Klassen unter „com.toptal.webpages“ und die Testroutinen unter „com.toptal.tests“.

Jetzt können wir damit beginnen, unsere Seitenobjektklassen zu erstellen.

Homepage-Seitenobjekt

Das allererste, das wir implementieren müssen, ist für die Homepage von Toptal (www.toptal.com). Erstellen Sie eine Klasse unter „com.toptal.webpages“ und nennen Sie sie „HomePage“.

 package com.toptal.webpages; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.How; import org.openqa.selenium.support.PageFactory; public class HomePage { private WebDriver driver; //Page URL private static String PAGE_URL="https://www.toptal.com"; //Locators //Apply as Developer Button @FindBy(how = How.LINK_TEXT, using = "APPLY AS A DEVELOPER") private WebElement developerApplyButton; //Constructor public HomePage(WebDriver driver){ this.driver=driver; driver.get(PAGE_URL); //Initialise Elements PageFactory.initElements(driver, this); } public void clickOnDeveloperApplyButton(){ developerApplyButton.click(); } }

Bestimmen von Elementlokatoren

Auf der Homepage von Toptal interessiert uns vor allem ein Element, und das ist der „Apply as a Developer“-Button. Wir können dieses Element finden, indem wir den Text abgleichen, was wir oben tun. Beim Modellieren von Webseiten als Seitenobjektklassen kann das Finden und Identifizieren von Elementen oft zu einer lästigen Pflicht werden. Mit den Debugging-Tools von Google Chrome oder Firefox kann dies erleichtert werden. Durch einen Rechtsklick auf ein beliebiges Element auf einer Seite können Sie die Option „Inspect Element“ aus dem Kontextmenü aktivieren, um detaillierte Informationen über das Element zu erhalten.

Eine gängige (und von mir bevorzugte) Möglichkeit besteht darin, Elemente mit der FireBug-Erweiterung von Firefox in Kombination mit dem Firefox-Webtreiber in Selenium zu finden. Nach der Installation und Aktivierung der FireBug-Erweiterung können Sie mit der rechten Maustaste auf die Seite klicken und „Element mit FireBug untersuchen“ auswählen, um FireBug zu öffnen. Auf der HTML-Registerkarte von FireBug können Sie den XPath, den CSS-Pfad, den Tag-Namen oder die „ID“ (falls verfügbar) eines beliebigen Elements auf der Seite kopieren.

Seitenobjektmodell in Selen: Bestimmung von Elementlokatoren

Indem wir den XPath des Elements im obigen Screenshot kopieren, können wir wie folgt ein WebElement-Feld dafür in unserem Seitenobjekt erstellen:

 @FindBy(xpath = "/html/body/div[1]/div/div/header/div/h1") WebElement heading;

Oder um die Dinge einfach zu halten, können wir hier den Tag-Namen „h1“ verwenden, solange er das Element, an dem wir interessiert sind, eindeutig identifiziert:

 @FindBy(tagName = "h1") WebElement heading;

DeveloperPortalPage-Seitenobjekt

Als nächstes brauchen wir ein Seitenobjekt, das die Seite des Entwicklerportals darstellt, eines, das wir erreichen können, indem wir auf die Schaltfläche „Als Entwickler bewerben“ klicken.

Auf dieser Seite haben wir zwei interessante Elemente. Um festzustellen, ob die Seite geladen wurde, möchten wir das Vorhandensein der Überschrift überprüfen. Und wir wollen auch ein WebElement -Feld für den „Join Toptal“-Button.

 package com.toptal.webpages; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; public class DeveloperPortalPage { private WebDriver driver; @FindBy(xpath = "/html/body/div[1]/div/div/header/div/h1") private WebElement heading; @FindBy(linkText = "JOIN TOPTAL") private WebElement joinToptalButton; //Constructor public DeveloperPortalPage (WebDriver driver){ this.driver=driver; //Initialise Elements PageFactory.initElements(driver, this); } //We will use this boolean for assertion. To check if page is opened public boolean isPageOpened(){ return heading.getText().toString().contains("Developer portal"); } public void clikOnJoin(){ joinToptalButton.click(); } }

DeveloperApplyPage-Seitenobjekt

Und schließlich definieren wir für unser drittes und letztes Seitenobjekt für dieses Projekt eines, das die Seite darstellt, die das Antragsformular für Entwickler enthält. Da wir es hier mit mehreren Formularfeldern zu tun haben, definieren wir für jedes Formularfeld eine WebElement- Variable. Wir finden jedes Feld anhand seiner „ID“ und definieren für jedes Feld spezielle Setter-Methoden, die Tastenanschläge für die entsprechenden Felder simulieren.

 package com.toptal.webpages; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; public class DeveloperApplyPage { private WebDriver driver; @FindBy(tagName = "h1") WebElement heading; @FindBy() WebElement developer_email; @FindBy() WebElement developer_password; @FindBy() WebElement developer_password_confirmation; @FindBy() WebElement developer_full_name; @FindBy() WebElement developer_skype; @FindBy() WebElement join_toptal_button; //Constructor public DeveloperApplyPage(WebDriver driver){ this.driver=driver; //Initialise Elements PageFactory.initElements(driver, this); } public void setDeveloper_email(String email){ developer_email.clear(); developer_email.sendKeys(email); } public void setDeveloper_password(String password){ developer_password.clear(); developer_password.sendKeys(password); } public void setDeveloper_password_confirmation(String password_confirmation){ developer_password_confirmation.clear(); developer_password_confirmation.sendKeys(password_confirmation); } public void setDeveloper_full_name (String fullname){ developer_full_name.clear(); developer_full_name.sendKeys(fullname); } public void setDeveloper_skype (String skype){ developer_skype.clear(); developer_skype.sendKeys(skype); } public void clickOnJoin(){ join_toptal_button.click(); } public boolean isPageOpened(){ //Assertion return heading.getText().toString().contains("Apply to join our network as a developer"); } }

Schreiben eines einfachen Selentests

Mit Seitenobjektklassen, die unsere Seiten darstellen, und Benutzerinteraktionen als ihre Methoden, können wir unsere einfache Testroutine jetzt als eine Reihe einfacher Methodenaufrufe und Zusicherungen schreiben.

 package com.toptal.tests; import com.toptal.webpages.DeveloperApplyPage; import com.toptal.webpages.DeveloperPortalPage; import com.toptal.webpages.HomePage; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxDriver; import java.net.URL; import java.util.concurrent.TimeUnit; public class ApplyAsDeveloperTest { WebDriver driver; @Before public void setup(){ //use FF Driver driver = new FirefoxDriver(); driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); } @Test public void applyAsDeveloper() { //Create object of HomePage Class HomePage home = new HomePage(driver); home.clickOnDeveloperApplyButton(); //Create object of DeveloperPortalPage DeveloperPortalPage devportal= new DeveloperPortalPage(driver); //Check if page is opened Assert.assertTrue(devportal.isPageOpened()); //Click on Join Toptal devportal.clikOnJoin(); //Create object of DeveloperApplyPage DeveloperApplyPage applyPage =new DeveloperApplyPage(driver); //Check if page is opened Assert.assertTrue(applyPage.isPageOpened()); //Fill up data applyPage.setDeveloper_email("[email protected]"); applyPage.setDeveloper_full_name("Dejan Zivanovic Automated Test"); applyPage.setDeveloper_password("password123"); applyPage.setDeveloper_password_confirmation("password123"); applyPage.setDeveloper_skype("automated_test_skype"); //Click on join //applyPage.clickOnJoin(); } @After public void close(){ driver.close(); } }

Ausführen des Tests

Zu diesem Zeitpunkt sollte Ihre Projektstruktur wie folgt aussehen:

Beispiel Selentest

Wenn Sie den Test ausführen möchten, wählen Sie „ApplyAsDeveloperTest“ aus der Baumstruktur aus, klicken Sie mit der rechten Maustaste darauf und wählen Sie dann „ApplyAsDeveloperTest“ ausführen aus .

Beispiel Selentest

Sobald der Test ausgeführt wurde, können Sie die Ergebnisse in der unteren linken Ecke Ihrer IDE sehen:

Beispiel Selentest

Fazit

Page Object und Page Factory machen es einfach, Webseiten in Selenium zu modellieren und automatisch zu testen, und machen das Leben von Entwicklern und QAs viel einfacher. Bei richtiger Ausführung können diese Seitenobjektklassen in Ihrer gesamten Testsuite wiederverwendet werden und geben Ihnen die Möglichkeit, frühzeitig automatisierte Selenium-Tests für Ihre Projekte zu implementieren, ohne die agile Entwicklung zu beeinträchtigen. Indem Sie Benutzerinteraktionen in Ihren Seitenobjektmodellen abstrahieren und Ihre Testroutinen leicht und einfach halten, können Sie Ihre Testsuite mit geringem Aufwand an sich ändernde Anforderungen anpassen.

Ich hoffe, ich konnte Ihnen zeigen, wie man schönen und sauberen Testcode schreibt, der einfach zu warten ist. Ich werde den Artikel mit meinem Lieblings-QA-Zitat beenden:

Zweimal überlegen, einmal programmieren!

Siehe auch: Web Scraping mit einem Headless Browser: Ein Puppeteer-Tutorial