Da wir in diesem zweiten Tutorial viel über Verbesserungen und Veränderungen unserer Testautomatisierung schreiben, ist es sinnvoll für Sie als Leser, dass vorhergehende Tutorial „Selenium Webdriver Tutorial 1“ zu kennen und den Stand des dort angelegten Selenium-Java-Projekts bis zum Ende ausprobiert zu haben.
ToDo Optimierungen des Selenium Codes
Eine Basis für strukturierten und wartbaren Code haben wir zum Teil in „Selenium Webdriver Tutorial 1“ bereits geschaffen, dennoch haben wir weiterhin „Code Smells“ (gut erklärt hier) bzw. Optimierungsbedarf, der uns in großen Testautomatisierungsprojekten schnell auf die Füße fallen würde. Die Probleme sind:
- Testdaten im Code (Beispiel: Login Daten). Eine Trennung von logischen und konkreten Testfällen ist anzustreben. (Auch Basis für Datengetriebene Testautomatisierung)
- Die Objekt-Referenzen sind aktuell in den Methoden und nicht zentral verwaltet. In den wiederverwendbaren Methoden ist dies schon mal besser aufgehoben als direkt in jedem Testfall. Aber noch besser wäre es, mehr Struktur rein zu bringen und die Objekt-Referenzen organisiert und zentral zu verwalten. Dazu werden wir nun ein Objekt-Repository
- Wir haben noch kein „Data-Driven-Framework“.
- Wir haben noch kein „Keyword-Driven-Framework“.
- Bisher kein echtes Cross Browser Testing
Was haben wir bereits: Start für Keyword-Driven-Test und Vermeidung Redundanz
Wir vermeiden doppelten, redundanten Code. Weiterhin haben wir eine entfernte Art von Keyword-driven-test-automation bereits geschaffen, auf einer höheren Granularität als einzelne Elemente bzw. einzelne Aktionen. Unsere Main Methode ist aktuell ziemlich simple. Mit folgendem Code, ist der logische Login-Testfall designet. Dazu ist dem Testfall-Designer egal, was in den Methoden ausgeführt wird. In unserem Fall decken die Methoden auch beispielsweise das dynamische Browser Handling und Verifikationen ab, was im Testfall selbst gar nicht sichtbar ist.
init_Browser(args); start_TBcom(); mainNav_LinkLoginRegister_Click(); page_loginRegister_FormLogin_FillSend(); secNavi_LinkTestautomatisierung_Click();
Wenn wir nun einen zweiten Testfall implementieren wollen und zur gleichen Webseite navigieren wollen, aber ohne dass der User sich zwischenzeitlich einloggt, brauchen wir nur zwei Schritte streichen.
init_Browser(args); start_TBcom(); secNavi_LinkTestautomatisierung_Click();
Hätten wir nun noch viele weitere Links, Pages und Formulare bereits in Methoden automatisiert, könnten wir mit weiteren Methoden schnell weitere Testfälle designen, ohne das der Testfall-Designer in die Funktionen rein schauen muss.
Das Problem bei unserer grob-granularen Art des Keyword-Driven-Testing ist, dass wir keine Zwischenschritte haben. Wir können mit gegebenen Methoden nicht designen, dass wir zum Login-Formular navigieren, nur das Formular ausfüllen, dann aber abbrechen und einen Link klicken. Denn wir haben ja nur die Methode „page_loginRegister_FormLogin_FillSend();“ und keine die nur befüllt (fill). Aus diesem Grund ist die Granularität des Keyword-Driven-Tests vorher zu planen. Meisten braucht es einzelne Schritte, aber auch grob granularer Schritte, um oft genutzte Funktionen wie den Gesamten Login-Vorgang, mit nur einer Zeile aufzurufen.
ToDo Verbesserung Keyword-Driven
Um zu einem echten Keyword-Driven-Testing-Framework zu kommen, müssen wir drei Dinge erledigen.
- Wir müssen die bisherigen Methoden der grobgranularen Teststep-Bundles noch aus der Testfall-Klasse selbst ziehen und für neue Testfälle verfügbar machen.
- Wir müssen neben den grob-granularen Teststeps auch fein-granulare zulassen, um einfacher Testfälle designen zu können.
- Eine Zeile bzw. ein Step eines Keyword-Driven Testfalles hat dann die Daten: „Objekt → Action → Parameter → Options“. Um das „Objekt“ zu bestimmen, wird sich dies in zwei Dinge teilen. Einmal in ein „Wo bin ich“, zum Beispiel auf der Login/Register-Page. Und zum anderen, um welches Objekt es sich handelt, zum Beispiel das Benutzername-Textfeld. Der Objekt-Name oder die Objekt-ID alleine reicht nicht, da sich Objekte mit gleichen Namen und gleichen IDs auf mehreren Pages befinden könnten.
- Wir müssen ein mögliches Testfall-Design aus dem Java-Code ziehen und ein Keyword-Driven-Testfall-Design in einem Excel oder anderen GUI-Tool ermöglichen. In diesem externen Tool zum Testfalldesign sollte man die Möglichkeit haben, die fein granularen Singlesteps zu verwende, aber auch die bereits vorhandenen grobgranularen Teststeps, welche wir fortan Teststep-Bundle nennen werden.
ToDo Verbesserung Data-Driven
In unserem ersten Login-Testfall sind die Login-Daten im Code „hard-coded“, also konkret im Code fest implementiert. Wir wollen aber Userdaten frei Verwalten können. Dazu sind zwei Dinge nötig.
- Entkoppeln der Testdaten (in unserem Fall bisher nur Login-Daten) aus den Testfallskripten und auch aus den Methoden der Teststeps.
- Die Testdaten aus externen Datenquellen ziehen, wie zum Beispiel Excel-Datenlisten, CSV-Dateien oder über TestNG (TestNG als DataProvider oder TestNG Parameter).
- Ermöglichen zu Testfällen spezifische Datensätze zu definieren, um beispielsweise einen Testfall mit 5 verschiedenen Datensätzen auszuführen.
ToDo Verbesserung Cross-Browser-Testing
Wir haben zwar Vorbereitungen getroffen und können einen Testfall ohne Anpassungen im Code über verschiedene Browser ausführen, aber nicht parallel. Hier fehlt noch ein echtes Cross-Browser-Testing Framework, welches Testfälle direkt in verschiedenen Browsern ausführt und am Ende einen Report gibt, mit welchen Browsern es korrekt oder auf Fehler lief. Dies zeigen wir später zum Beispiel mit TestNG.
Umsetzung der Verbesserung Step 1 – Komplett neues Design unseres Selenium Testframeworks
Da wir alles Schritt für Schritt umsetzen wollen, um verschiedene Möglichkeiten zu zeigen, geht es in kleinen Schritten weiter. Aus der vorherigen Liste angestrebter Verbesserungen und Optimierungen setzen wir nun um:
- Verbesserung Struktur: Die Objekt-Referenzen sind aktuell in den Methoden und nicht zentral verwaltet. Dies muss geändert werden.
- Verbesserung Data-Driven 1: Entkoppeln der Testdaten (in unserem Fall bisher nur Login-Daten) aus den Testfallskripten und auch aus den Methoden der Teststeps. Eine Trennung von logischen und konkreten Testfällen ist anzustreben.
- Verbesserung Keyword-Driven 1: Wir müssen die bisherigen Methoden der grob-granularen Teststep-Bundles noch aus der Testfall-Klasse selbst ziehen und für neue Testfälle verfügbar machen.
- Verbesserung Keyword-Driven 2: Wir müssen neben den grob-granularen Teststeps auch fein-granulare zulassen, um einfacher Testfälle zu designen.
Dazu starten wir ein neues Projekt in Eclipse, da sich das Design des Selenium Testframeworks nun grundlegend ändert.
Klasse tbCom_User
In Objekt-Orientierter Manier legen wir nun eine Klasse für einen User an. Ein User des Testing-Board hat für unsere Testfälle drei relevante Attribute.
- Benutzername
- Passwort
- Berechtigung bzw. Rolle im WordPress CMS
Die neue Klasse sieht somit wie folgt aus:
tbCom_User.java
public class tbCom_User { String username; String password; String role; public tbCom_User getAdmin() { username = "TestAdmin"; password = "xxx"; role = "Admin"; return this; } public tbCom_User getNormal() { username = "TestUser"; password = " xxx"; role = "Normal"; return this; } }
Damit entkoppeln wir schon mal weiter die Testdaten vom restlichen Code, von der Testautomatisierungs-Technik wie auch vom Testfall. Echtes Data-Driven haben wir weiterhin noch nicht, dies ist auch erst der erste und kleinste Schritt aus der oberen ToDo mit Verbesserungen im Bereich Data-Driven. Es wäre nun sehr leicht, die Daten in der tbCom_User aus einer externen Datei zu lesen oder bestimmte fachliche Algorithmen einzubauen.
Klasse der Webelemente
Weiterhin überlegen wir uns Klassen der einzelnen WebElemente, um in einem neuen Objekt-Repository, die jeweiligen Daten zur Objekt-Identifizierung speichern zu können. Dabei soll eine Element-Klasse die Daten umfassen, die wir zum WebElement speichern können möchten und auch die Funktionen enthalten, die wir zu dem Element anbieten möchten. Durch das Anbieten der Funktionen muss der Testfall-Ersteller sich dann keine Gedanken mehr um die Objekterkennung machen. Alle Elemente packen wir der Übersicht halber in ein Package namens „Elements“.
tbCom_element_textfield.java
package Elements; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; public class tbCom_element_textfield { public String id; public String name; public String xpath; public WebElement findElement(WebDriver driver) { WebElement element = driver.findElement(By.id(id)); return element; } public void type(WebDriver driver, String text) { findElement(driver).sendKeys(text); } public void clear(WebDriver driver) { findElement(driver).clear(); } }
Über diese Klasse tbCom_element_textfield haben wir nun unser eigenes Textfeld definiert. Wir haben auch definiert wie wir Textfelder identifizieren möchten und welche Attribute wir zu einem Textfeld im Objekt-Repository abspeichern wollen. Wir speichern direkt id, name und xpath ab. Auch wenn wir zunächst nur anbieten nach ID zu identifizieren. Wir könnten somit auch kurzer Hand ein clear_byXPath anbieten, falls jemand es bräuchte.
Nun definieren wir noch Link und Button für unsere Selenium WordPress Testautomatisierung.
tbCom_element_button.java
package Elements; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; public class tbCom_element_button { public String id; public String value; public String name; public String xpath; public WebElement findElement(WebDriver driver) { WebElement element = driver.findElement(By.id(id)); return element; } public void submit(WebDriver driver) { findElement(driver).submit(); } }
tbCom_element_Link.java
package Elements; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; public class tbCom_element_Link { public String id; public String xpath; public WebElement findElement(WebDriver driver) { WebElement element = driver.findElement(By.id(id)); return element; } public void click(WebDriver driver) { findElement(driver).click(); } }
Klassen im Object-Repository
Für unser Objekt-Repository teilen wir die Webseite in Bereiche und überlegen uns, was wir für Methoden für diese Bereiche anbieten wollen und welche Objekte/Elemente wir in diesem Bereichen automatisiert ansprechen wollen. Daraus erstellen wir ein Repository an Objekt-Referenzen. Unsere Klassen im Objekt-Repository sind Bereiche der Webseite und diese wiederum bestehen aus den zuvor erstellten Element-Klassen.
Auf UML verzichten wir an der Stelle und verweisen auf folgendes Diagramm, was dies intuitv veranschaulichen soll.
An dieser Stelle könnte man sich eine Matrix machen, welche Elemente man auf der Webseite automatisieren möchte und welche Veränderungen / Aktionen man an diesen Objekten durchführen möchte.
Weiterhin ist zu beachten, dass wir die Main-Navigationsleiste und Second-Navigationsleiste natürlich auch von der Login/Register-Page aus sehen. Für diese immer sichtbaren Navigations-Elemente werden wir aber eigene Klassen anlegen. Diese Navigations-Leisten haben mit der Login/Register-Page ja nicht direkt was zu tun, auch wenn wir diese von der Seite aus drücken können. Beide Navigationsleisten stehen uns auch auf allen anderen Pages zur Verfügung. Aus diesem Grund bekommen sie eigene Klassen im Objekt-Repository.
Auch unser Object-Repository verwalten wir zunächst in dem Selenium Java-Code selbst. Der erste Schritt legt das Objekt-Repository und damit alle Objekt-Referenzen mit denen Objekte bei der Testautomatisierung identifiziert werden zentral ab. Dazu starten wir ein neues Package mit Bezeichnung „ObjectRepository“, um es übersichtlicher zu organisieren.
Nun erstellen wir eine Klasse, um unsere WordPress Login/Register-Page zu repräsentieren. Dort fügen wir Objekt-Referenzen zu allen Objekten hinzu, die der Content der Page bietet. Wobei wir uns hier zunächst auf die Objekte beschränken, die wir im aktuellen Testfall bisher nutzen. Von unserer WordPress Login/Register-Page nehmen wir zunächst nur Textfelder Username / Password und den Submit-Button in das Objekt-Repository.
tbCom_objectrepository_Page_LoginRegister.java
package ObjectRepository; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.testng.Assert; import Elements.tbCom_element_button; import Elements.tbCom_element_textfield; public class tbCom_objectrepository_Page_LoginRegister { public tbCom_element_textfield tfUsername; public tbCom_element_textfield tfPassword; public tbCom_element_button bButtonLogin; public tbCom_objectrepository_Page_LoginRegister() { tfUsername = new tbCom_element_textfield(); tfUsername.id = "user_login"; tfUsername.name = "log"; tfUsername.xpath = "/html/body/div/div/article/div/div/div/div[3]/span/form/p[1]/input"; tfPassword = new tbCom_element_textfield(); tfPassword.id = "user_pass"; tfPassword.name = "pwd"; tfPassword.xpath = "/html/body/div/div/article/div/div/div/div[3]/span/form/p[2]/input"; bButtonLogin = new tbCom_element_button(); bButtonLogin.id = "wp-submit"; bButtonLogin.name = "wp-submit"; bButtonLogin.value = "Anmelden"; bButtonLogin.xpath = "/html/body/div/div/article/div/div/div/div[3]/span/form/p[4]/input[1]"; } public void clearAll(WebDriver driver) { tfPassword.clear(driver); tfUsername.clear(driver); } public void submitAndVerify(WebDriver driver) { bButtonLogin.submit(driver); /*verify logged-in correctly, alternatively check page title, images, etc. */ String fullBodyText = driver.findElement(By.tagName("body")).getText(); Assert.assertTrue(fullBodyText.contains("Sie sind bereits eingeloggt!"), "Login Text not found!"); } }
Wir speichern zu den Objekten auf der Login/Register-Page verschiedene Attribute. Somit können wir schnell zu verschiedenen Identifizierungsarten wechseln, wie wir in den Element-Klassen bereits gesehen haben. Aktuell für uns am wichtigsten, das Attribut „ID“. Somit speichern wie die ID von den Textfeldern und dem Submit-Button nun ganz zentral, an einer Stelle, an der sich alle WebElemente der Login/Register-Page befinden.
Wenn wir nun erweiterte Funktionen hinzufügen und anbieten, wie beispielsweise das „submitAndVerify“ aus dem obigen Code-Beispiel, dann braucht man keine eigene Verifikation im Testfall mehr implementieren. Und ändert sich die Verifikation nach dem erfolgreichen Login, ist diese auch nur an einer einzigen Stelle anzupassen.
Nach gleichem Prinzip sind nun auch die Haupt-Navigations-Leiste und die Sekundäre- Navigations-Leiste ins Object-Repository geflossen. Nur brauchen wir hier kaum extra Methoden, da wir nur normale Klicks ohne Verifikationen nutzen. Das simple „Klicken“ wird sozusagen bereits über die Element-Klasse geliefert.
Bei beiden Navigationsleisten nehmen wir zunächst nur einige der Links aus den Leisten ins Objekt-Repository.
tbCom_objectrepository_MainNaviBar.java
package ObjectRepository; import Elements.tbCom_element_Link; public class tbCom_objectrepository_MainNaviBar { public tbCom_element_Link lnkHome; public tbCom_element_Link lnkZiele; public tbCom_element_Link lnkLoginRegister; public tbCom_objectrepository_MainNaviBar() { lnkHome = new tbCom_element_Link(); lnkHome.id = "menu-item-389"; lnkHome.xpath = "/html/body/header/div[1]/nav/ul/li[1]"; lnkZiele = new tbCom_element_Link(); lnkZiele.id = "menu-item-517"; lnkZiele.xpath = "/html/body/header/div[1]/nav/ul/li[2]"; lnkLoginRegister = new tbCom_element_Link(); lnkLoginRegister.id = "menu-item-826"; lnkLoginRegister.xpath = "/html/body/header/div[1]/nav/ul/li[3]"; } }
tbCom_objectrepository_SecondNaviBar.java
package ObjectRepository; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.testng.Assert; import Elements.tbCom_element_Link; public class tbCom_objectrepository_SecondNaviBar { public tbCom_element_Link lnkHome; public tbCom_element_Link lnkTestautomatisierung; public tbCom_element_Link lnkLastUndPerformancetest; public tbCom_objectrepository_SecondNaviBar() { lnkHome = new tbCom_element_Link(); lnkHome.id = "menu-item-1357"; lnkHome.xpath = "/html/body/header/div[2]/div/div[2]/nav/ul[1]/li[1]"; lnkTestautomatisierung = new tbCom_element_Link(); lnkTestautomatisierung.id = "menu-item-695"; lnkTestautomatisierung.xpath = "/html/body/header/div[2]/div/div[2]/nav/ul[1]/li[2]"; lnkLastUndPerformancetest = new tbCom_element_Link(); lnkLastUndPerformancetest.id = "menu-item-634"; lnkLastUndPerformancetest.xpath = "/html/body/header/div[2]/div/div[2]/nav/ul[1]/li[3]"; } public void ClickTestautomatisierungAndVerify(WebDriver driver) { lnkTestautomatisierung.click(driver); /* verify Page is loaded correctly */ String fullBodyText = driver.findElement(By.tagName("body")).getText(); Assert.assertTrue(fullBodyText.contains("Testautomatisierung ist ein automatisiertes Testverfahren"), "Text on Page Testautomatisierung not found!"); } }
In der SecondNaviBar bieten wir wieder eine Funktion mit Verifikationspunkt an. Für einen Klick von „Testautomatisierung“ bräuchten wir keine extra Methode, dies würde die Element-Klasse anbieten. Aber so können wir eine Funktion anbieten, die das Klicken ermöglicht und gleich beinhaltet es zu verifizieren (Methode ClickTestautomatisierungAndVerify). Vorteil: Wenn sich die Verifikationsmethode ändert, braucht man es nur an einer Stelle ändern. Und in jedem Testfall, indem der Link geklickt wird, muss kein eigen definierter Verifikationspunkt mehr erstellt werden.
Fazit Element-Klassen und Objekt-Repository
In den Elemente-Klassen können wir nun an einer Stelle austauschen, wie die Objekt-Referenzierung aussehen soll. Weiterhin speichern wir in den Instanzen im Objekt-Repository zu den konkreten Objekten auch direkt Attribute wie Xpath, ID und Name ab. Somit können wir auch bei Bedarf schnell auf Referenzierung über andere Arten wechseln. Wir könnten auch, wenn es nötig ist, Funktionen wie Submit_ReferenceByID und Submit_ReferenceByXPath gleichzeitig anbieten.
Die ganze Referenzierung und Technik der Selenium Testautomatisierung steckt somit in den Element-Klassen und Object-Repository-Klassen. Alles was diese Klassen bereits anbieten, kann man nun für Automatisierte TestCases und Teststep-Bundles verwenden. Und alles was diese Klassen anbieten, muss bei Design oder Codeänderungen (ID Änderung) nicht in jedem Testfall, sondern nur einmal in der ObjectRepository-Klasse und/oder in der Element-Klasse nachgepflegt werden.
Verbesserung Keyword-Driven, Testfälle und Teststep-Bundle
Nun haben wir die Grundlage, um die Testfälle und auch die Teststep-Bundle zu optimieren. Die Teststep-Bundle (grobgranularen Keyword-Methoden , wir nennen sie Teststep-Bundle) hatten wir in dem letzten Projekt noch in dem Testfall (ausführbares Testskript) selbst enthalten. Diese sind nun ausgelagert in eine neue „tbCom_CompleteTeststepBundle“.
In dieser Klasse sollen alle grob-granularen Teststeps eingebunden werden, die meist mehrere einzelne Steps umfassen. In einzelnen ausführbaren Testskripten, welche die Testfälle bzw. Testszenarien darstellen, können diese Teststep-Bundles dann genutzt werden.
Die Klasse des Teststep-Bundle sieht wie folgt aus.
tbCom_CompleteTeststepBundle.java
import java.util.concurrent.TimeUnit; import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxDriver; import ObjectRepository.tbCom_objectrepository_Page_LoginRegister; import ObjectRepository.tbCom_objectrepository_MainNaviBar; import org.openqa.selenium.chrome.ChromeDriver; public class tbCom_CompleteTeststepBundle { /* * @param args arg 0 = Browser: "Chrome", "Firefox" arg 1 = User Role: * "Normal", "Admin" */ public WebDriver driver; static tbCom_User user; public void init_Browser(String[] args) throws Exception { String browser = null; if (args.length == 0) { System.out.println("No Browser Parameter given, use default Browser Firefox"); browser = "Firefox"; } else { browser = args[0]; } if (browser.equalsIgnoreCase("Firefox")) { driver = new FirefoxDriver(); } else if (browser.equalsIgnoreCase("Chrome")) { String pathToChromeDriver = ".//ChromeDriver//chromedriver_Win_220.exe"; System.setProperty("webdriver.chrome.driver", pathToChromeDriver); driver = new ChromeDriver(); } else { System.out.println("Browser not defined!"); throw new Exception("Browser not defined!"); } driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS); } public void start_TBcom() { String URL = "http://www.testing-board.com"; driver.get(URL); } public void page_LoginRegister_Form_Login_FillSend(String[] args) { String user_args = null; if (args.length <= 1) { System.out.println("No User Parameter given, get defaut Normal User"); user_args = "Normal"; } else { user_args = args[1]; } if (user_args.equalsIgnoreCase("Normal")) { user = new tbCom_User().getNormal(); } else if (user_args.equalsIgnoreCase("Admin")) { user = new tbCom_User().getAdmin(); } else { System.out.println("User not defined!"); return; } tbCom_objectrepository_Page_LoginRegister Page = new tbCom_objectrepository_Page_LoginRegister(); Page.tfUsername.type(driver, user.username); Page.tfPassword.type(driver, user.password); Page.submitAndVerify(driver); } public void Start_and_Login(String[] args) throws Exception { init_Browser(args); start_TBcom(); tbCom_objectrepository_MainNaviBar MainNaviBar = new tbCom_objectrepository_MainNaviBar(); MainNaviBar.lnkLoginRegister.click(driver); page_LoginRegister_Form_Login_FillSend(args); } }
Der neue TestCase
Der neue TestCase nutzt die oben beschriebenen Elemente. Um den Testfall wie folgt zu designen, muss man sich keine Gedanken um Objekt-Referenzen machen, da alles auf das vorhandene Objekt-Repository zugreift.
Testcase_two_Login_with_clear_wrong_input_meanwhile.java
import ObjectRepository.tbCom_objectrepository_MainNaviBar; import ObjectRepository.tbCom_objectrepository_Page_LoginRegister; import ObjectRepository.tbCom_objectrepository_SecondNaviBar; public class Testcase_two_Login_with_clear_wrong_input_meanwhile { /* * @param args * arg 0 = Browser: "Chrome", "Firefox" * arg 1 = User Role: "Normal", "Admin" * * * Test Case go to Login Page and enters wrong credentials * User deletes wrong credentials * User enter correct credentials * User close Browser * User go again to Login and enter correct credentials directly * * */ public static void main(String[] args) throws Exception { tbCom_CompleteTeststepBundle test = new tbCom_CompleteTeststepBundle(); test.init_Browser(args); test.start_TBcom(); tbCom_objectrepository_MainNaviBar MainNaviBar = new tbCom_objectrepository_MainNaviBar(); MainNaviBar.lnkLoginRegister.click(test.driver); /* Special Scenario, first enter Wrong Credentials, then delete, then enter again*/ tbCom_objectrepository_Page_LoginRegister LoginRegisterPage = new tbCom_objectrepository_Page_LoginRegister(); LoginRegisterPage.tfUsername.type(test.driver, "Wrong Username"); LoginRegisterPage.tfPassword.type(test.driver, "Wrong PW"); Thread.sleep(2000); LoginRegisterPage.clearAll(test.driver); Thread.sleep(2000); test.page_LoginRegister_Form_Login_FillSend(args); tbCom_objectrepository_SecondNaviBar SecondNaviBar = new tbCom_objectrepository_SecondNaviBar(); SecondNaviBar.ClickTestautomatisierungAndVerify(test.driver); /* Close browser*/ test.driver.close(); /* Start and Login again with TeststepBundle Start_and_Login */ test.Start_and_Login(args); } }
Der TestCase sollte sich nun ganz normal und ohne Fehler ausführen lassen. Werden keine Argumente übergeben, werden Firefox und Credentials des Normal-User verwendet. Es lassen sich aber auch weiterhin der verwendete Browser (Chrome|Firefox) und der User (Normal|Admin) als zwei Argumente beim Aufruf des Testfalls übergeben.
Unser Selenium Projekt in Eclipse müsste nun wie folgt aussehen:
Aktuelle Vorteile und Status des neuen Selenium Testautomatisierungs-Designs
Die Vorteile sieht man schnell, wenn man sich den Testfall ansieht und versucht neue Steps zuzufügen. Die Eclipse IDE hilft auch dabei. Hier ein Beispiel.
Wenn wir im Testfall „LoginRegisterPage.“ schreiben, zeigt Eclipse uns direkt die Elemente aus unseren Objekt-Repository:
In unserem Fall haben wir für die Login/Register-Page bereits zwei Textfelder und ein Button integriert. Diese zeigt uns Eclipse direkt an (wie oben zu sehen). Wir sehen also direkt, was uns die Login/Register-Page anbietet und was wir bereits automatisiert abgebildet haben und direkt nutzen können.
Wählen wir nun davon ein WebElement-Objekt aus, sodass im Code „LoginRegisterPage.tfPassword“ steht („tf“ steht für textfield), zeigt uns die Eclipse IDE direkt was wir mit dem Password-Textfeld machen können. Dort sind auch unsere angebotenen Methoden bei, type (tippen), clear (leeren). Und dieses, ohne dass wir eine Objekt-Referenz angeben müssen. Wir können auch direkt auf die Attribute unseres Elements im Objekt-Repository zugreifen, auf die ID oder den gespeicherten Xpath.
Auf diese Art können wir mit allen Elementen aus dem Objekt-Repository sehr komfortabel und mit geringen Programmierkenntnissen weitere Testfälle zusammenstellen.
Den Vorteil, dass wir beim Aufruf des Testfalls den Browser und ausführenden User-Account über Parameter bestimmen können, haben wir weiterhin. Nun können wir eine beliebige weitere Java-Klasse mit einem Testszenario erstellen, bestehend aus den bereits realisierten, automatisierten Links, Formularen Teststep-Bundles. Und dies mit Browser und User der Wahl ausführen.
Beispiel Vorteil Teststep-Bundle Login
Auch die Teststep-Bundle nehmen uns Arbeit bei der Testfallerstellung ab, bei allen Steps die häufig vorkommen. Beispielsweise haben wir im Teststep-Bundle nun die Methode „Start_and_Login“, die wir im obigen Testfall nun auch nutzen. Diese Methode übernimmt alles von Browser-Initialisierung, Webseiten-Start, Navigation-zum-Login und dem Login selbst. Diese „Start_and_Login“ Methode wird also in allen Testfällen vorkommen, die ein Login am Anfang benötigen, was im Normalfall viele sind. Und dazu bedarf es nur einer einzelnen Zeile im Testfall.
Exkurs: Verifications
In diesem Tutorial verwenden wir wenige Verifizierungen, wenige Kontrollen, ob unsere Webseiten das anzeigen, was sie sollen. Alles was geprüft werden soll, können wir Selenium mitgeben. Dies können wir über XPath Pfade im DOM-Baum sein, Attribute bestimmter Elemente auf der Webseite oder über Text im HTML. Auch das Design lässt sich mit bestimmten Einschränkungen verifizieren.
Selenium Tutorial Ausblick: Was kommt demnächst
- Bei Data-Driven, Keyword-Driven haben wir weitere rudimentäre erste Vorbereitungen abgedeckt, aber viele bereits angesprochene Punkte sind noch offen. Dies setzen wir nach und nach um, bis zu einem echten hybriden Data-Driven und Keyword-Driven Testframework.
- Wir zeigen Test Reporting mit TestNG aus Eclipse heraus.
- Data-Driven über Excel und TestNG (Parameter, Dataprovider)
- Testfälle über HP ALM 12 ausführen und das Testergebnis wieder zurück in ALM bekommen und dort anzeigen.
Sehr gutes Tutorial durch dessen hilfe ich eigene Erfolge im Bereich Unit-Testing erreichen konnte. Die Integration von TestNG in HP ALM wäre eine weitere spannede Aufgabe die mein Interesse geweckt hat.
Ich freue mich auf weitere gute Tutorials.
Alles sehr spannend und hilfreich!
Wann können wir denn mit dem Selenium Webdriver Tutorial 3-5 rechnen?
Hallo Havva,
leider sind alle „Redakteure“ eher in IT-Projekte versunken und es gibt deswegen leider nur wenige Artikel im Jahr, dazu stark verteilt auf die Themen des Boards oder eher in Pflege vorhandener Artikel.
Die fehlenden Selenium-Themen wären in der Tat sehr spannend. Auch Dinge wie Selenium mit TestNG, die Nutzung von Annotations zur Vereinfachung der Selenium-Code-Struktur und mal ein Beispiel mit Zugsamenhang zu Frameworks wie Selenide wären schön. Aktuell kann ich nur anbieten, dass jemand der Interesse hat, sich meldet und gerne einen Selenium-Artikel veröffentlichen kann.
Liebe Grüße
Sebastian