Selenium WebDriver

MPDL

Autor: Yan Yao

Ansprechpartner: Yan Yao

Zuletzt aktualisiert am: 13.12.2013

Stichwörter: Testautomatisierung, Webanwendung, Cross-Browser Testing, Selenium Webdriver, Maven, TestNG, Xpath, CSS Selector

Ich habe Selenium WebDriver zum Durchführen automatisierter Browser Tests von entschieden. Hier möchte ich gerne meine Erfahrungen mitteilen, welche Probleme aufgetreten sind und wie ich sie gelöst habe.

=Über AWOB= =Über Selenium= =Testumgebung und verwendete Tools= AWOB ist in Java entwickelte Webanwendung. Deswegen benutze ich Selenium WebDriver mit Java 1) das Java-Archiv für Selenium Client Driver herunterladen, entpacken und die .jar Dateien in Buildpath hinzufügen, z.B. unter Eclipse erstellt man ein Java Projekt und fügt die .jar Dateien als external JARs hinzu.
 * AWOB ist eine web-basierte Anwendung und eine wissenschaftliche Projektmanagementplattform für Kollaboration, Kommunikation, Koordination, Datenaustausch und elektronische Publizieren der Wissenschaftlern mit granularen Zugriffsrechten (lead, manger, project manager, member) und Abbildungsmöglichkeiten komplexer Hierarchien (momentan 4 „work spaces“: consortium, project, task, group).
 * Meine Aufgaben im Projekt: Automatisierung von GUI-Tests und funktionalen Tests
 * Probleme für automatisiertes Testen des Projektes
 * Schwierigkeit bei der Webelement-Identifikation: es gibt kein eindeutige Lokatoren im HTML-Quelltext, dynamische IDs
 * Langsamer Webserver: das Herunterladen der kompletten Webseite dauert so lange, dass einige Elemente in der Webseite nicht gefunden werden.
 * Komplexität der Strukturierung: die verschiedenen Portlets sind ineinander verschachtelt. Einige Komponenten aus unterschiedlichen Portlets werden wegen der ähnlichen Funktionalität die gleichen Klassennamen gegeben. Es erschwert die Lokalisierung der Webelemente.
 * Cross-Browser- und Cross-Plattform-Kompatibilität: das automatisierte Testen soll mit verschiedenen Browsern (Firefox, IE, Chrome, Safari etc.) und verschiedenen Plattformen (Windows, Linux, OS X etc.) durchgeführt werden.
 * Warum Selenium?
 * Selenium basiert auf HTML und JavaScript. Deshalb unterstützt Selenium viele verschiedene Browser auf vielen verschiedenen Plattformen und auch viele Entwicklungssprachen.
 * Als Open Source wird Selenium von der Community weiterentwickelt und gepflegt.
 * Warum Selenium WebDriver?
 * Selenium WebDriver ist eine objektorientiertere API und nicht an ein spezielles Testframework gebunden.
 * Selenium WebDriver leitet die Befehle an dem Browser weiter und steuert durch den browserspezifischen Treiber (WebDriver) den Browser direkt.
 * Installation von Selenium WebDriver mit Java: es gibt zwei Möglichkeiten, Selenium WebDriver in das Projekt einzubinden.

2) Selenium WebDriver mittels Build-Management-Tool Maven erstellen, z.B. unter Eclipse erstellt man ein Maven Projekt und fügt das Dependency von Selenium WebDriver im pom.xml hinzu (ich habe zur Zeit die Version 2.35.0 benutzt. Die aktuelle Version kann man unter dem Link http://docs.seleniumhq.org/download/ herunterladen). In AWOB habe ich Selenium WebDriver mit Maven integriert.

org.seleniumhq.selenium selenium-java 2.35.0            org.seleniumhq.selenium selenium-server 2.35.0


 * Installation von TestNG: Um die automatisierten Tests leichter zu verwalten und durchzuführen, habe ich TestNG, ein Testframework für Unit-Tests, mittels Maven installiert.

org.testng testng 6.1.1            test


 * Installation von Treiber für Browser: Um verschiedene Browsern zum Testen zu benutzen muss der browserspezifische Treiber heruntergeladen und installiert werden. Der Treiber muss vor dem Durchführen vom einzelnen Test gestartet werden.
 * Firefox: ist der Standard-Browser für Selenium. Das heißt es muss nichts installiert werden und die Tests können sofort gestartet werden.
 * Chrome: Wiki für Installation von Chrome Driver http://code.google.com/p/selenium/wiki/ChromeDriver
 * InternetExplorer: Wiki für Installation von Internet Explorer Driver http://code.google.com/p/selenium/wiki/InternetExplorerDriver (nur für Windows)
 * Safari: Wiki für Installation von Safari Driver http://code.google.com/p/selenium/wiki/SafariDriver

=Selenium-Tests als TestNG Unit-Tests=

TestNG ist ein Testframework für automatisierte Unit-Tests und ist eine leistungsfähigen Alternative zu JUnit. Im Vergleich zu JUnit hat TestNG folgende


 * Vorteile:
 * Tests lassen sich fein in sehr kleine Einheiten gruppieren.
 * Sie können zwischen verschiedenen Gruppen von Tests umfangreiche Abhängigkeiten spezifizieren, die die Ausführungsreihenfolge festlegen.
 * Tests können nicht nur mit Ant, sondern auch mit einem eigenen leichtgewichtigen XML-Dokument spezifiziert werden.
 * Im Gegensatz zu JUnit arbeiten die Testmethoden auf denselben Instanzen, die Testmethoden erzeugen also nicht immer neue Instanzen.
 * Nebenläufigkeitstests werden out-of-the-box unterstützt.
 * Detailliertes Reporting: Der TestNG-Report gibt ausführlich über Ergebnisse und Testreihenfolgen Aufschluss.


 * Nachteile:
 * Tests können nicht als Plugin-Tests durchgeführt werden, was aber notwendig sein kann, wenn Sie Eclipse RCP- bzw. OSGi-Anwendungen schreiben.
 * Die Tool-Unterstützung zur Nutzung aus einer IDE ist derzeit noch nicht ganz so gut wie bei JUnit. Obwohl es für TestNG
 * Plugins zur Nutzung aus einer IDE gibt, ist die JUnit-Unterstützung häufig out-of-the-box vorhanden.
 * Merkmale:
 * Testmethoden können mit Parametern aufgerufen werden und parametrisiert werden.
 * TestNG kann JUnit-Tests laufen lassen.
 * Fehlgeschlagene Tests können separat erneut gestartet werden.
 * TestNG kann JUnit-konforme Reports erzeugen.

=TestNG-Annotationen= TestNG ermöglicht eine vielfältige Steuerung der Tests und Testmethoden mittels Annotationen. Hier findet man eine Liste der verfügbaren Annotationen.

=Steuerung der Browser=

Die Browser zum Testen können in TestNG mittels Parameter gesteuert werden und durch eine If-Else Bedienung in einer Annotation @BeforeMethod entschieden werden, die vor jedem Test aufgerufen wird.

@BeforeMethod @Parameters({ "browser" }) public void openBrowser(String browser) throws Exception { if (browser.equals("Firefox")) { driver = new FirefoxDriver; //default, Firefox ist Standard Browser } else if (browser.equals("InternetExplorer")) { // für andere Browser muss das System Property zu jedem Treiber gesetzt werden System.setProperty("webdriver.ie.driver",”path of internet explorer driver”); driver = new InternetExplorerDriver; } else if (browser.equals("Chrome")) { System.setProperty("webdriver.chrome.driver", "path of chrome driver"); driver = new ChromeDriver; } else if (browser.equals("Safari")) { System.setProperty("webdriver.safari.driver", "path of safari driver"); driver = new SafariDriver; }     }

Um die Browser zu schließen wird eine Annotation @AfterMethod wird geschrieben, die nach jedem Test aufgerufe wird.

@AfterMethod public void closeDriver throws Exception { driver.close; }

=Kleines Test-Beispiel=

Hier wird die URL für Google in der Browser eingegeben und das Keyword "selenium webdriver" gesucht.

@Test(groups ={"google search test"}) public void googleSearch { driver.get("http://www.google.com"); driver.findElement(By.name("q")).sendKeys("selenium webdriver"); driver.findElement(By.name("btnG")).click; }

=TestNG.XML=

Neben den Annotationen können die Tests in TestNG über ein XML-Dokument zusammengestellt und gruppiert werden. Anhand von vorliegender Beispiele sieht ein Test der Google-Suche in Firefox wie folgt aus:

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">     <class name="TestDemo"/>

=Auswahl der Webelementen=

Im vorliegenden Test-Beispiel werden die Elemente auf der Google-Seite nach ihren Namen gefunden und gesteuert. Außerdem bietet Selenium viele andere Möglichkeiten, die Webelemente zu lokalisieren wie xpath, CSS-Selektoren, ID, Name, Linktext, Klassenname u.s.w.

WebElement element = driver.findElement(By.id("eindeutige_id")); WebElement element = driver.findElement(By.name("name")); WebElement element = driver.findElement(By.tagName("tagname")); WebElement element = driver.findElement(By.className("classname")); WebElement element = driver.findElement(By.linkText("linktext")); WebElement element = driver.findElement(By.partialLinkText("part of link")); WebElement element = driver.findElement(By.cssSelector("div#id");   List<WebElement> inputs = driver.findElements(By.xpath("//input")); // für eine List von Elementen

Für AWOB benutze ich hauptsächlich zwei Selektoren, um die Webelementen festzulegen, nähmlich xpath und CSS-Selektor. Die Vorteile der CSS-Selektoren sind: - Sie sind schnell und für den Entwickler leserlich. - Sie sind sehr robust bei Ajax. - Sie bieten einige von jQuery bekannte Hilfs-Selektoren an. - Sie sind konsistent und haben gleichmäßige Performance in verschiedenen Browser.

Der Grund für die Verwendung von xpath ist: CSS-Selektoren unterstützen es nicht, die Elementen durch den Text zu finden, z. B. zwei Elementen innerhalb eines HTML-Blocks auf der Webseite haben den gleichen Klassenname und ihre IDs sind dynamisch. Mittels xpath ist es möglich, die Elementen zu unterscheiden und das gewollte Element herauszufinden.

WebElement element = driver.findElement(By.xpath("//*[contains(text,'text')]"));

=Finden von CSS und HTML-Elementen=

Um die CSS und HTML-Elementen auf der Webseite herauszufinden, werden Firebug für Firefox, Chrome und Developer Toolbar für Internet Expolrer verwendet. Für Safari wählt man einfach die Option “Menü Entwickler in der Menüleiste anzeigen” unter “Einstellungen” -> “Erweitert” aus und wird die Option "Element Informationen" danach durch den rechten Mausklick angezeigt. Laden von Webseite und Webelementen

Bei AWOB dauert das Laden von Webseite und -elementen lange. Es gibt einige Möglichkeiten, um dieses Problem zu lösen: driver.manage.timeouts.implicitlyWait(20, TimeUnit.SECONDS); 1) Warten auf komplette Webseiten herunterladen      public static void waitForPageLoaded(WebDriver driver) {                    ExpectedCondition<Boolean> pageLoadCondition = new ExpectedCondition<Boolean> {                      public Boolean apply(WebDriver driver) {                               return ((JavascriptExecutor) driver).executeScript( "return document.readyState").equals("complete");                                }                  };                 WebDriverWait wait = new WebDriverWait(driver, 10);                 try { wait.until(pageLoadCondition);                 } catch (Throwable error) {           Assert.assertFalse(true, "Timeout waiting for Page Load Requese to complete.");                 }        } 2) Warten auf Element herunterladen public static void waitElementPresent(WebDriver driver, By locator){ WebDriverWait wait = new WebDriverWait(driver, 10); wait.until(ExpectedConditions.visibilityOfElementLocated(locator)); }
 * implicit wait
 * explicit waits

Weitere Erklärung von "Explicit and Implicit Wait" in Selenium WebDriver: http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp#explicit-and-implicit-waits

=Klicken der Webelementen via JavaScript=

Oft wird das Klicken click in Selenium Webdriver nicht richtig funktionniert. Deswegen wird eine Click-Method via JavaScript implementiert:

public static void clickElement(WebDriver driver, By locator){ WebElement element = driver.findElement(locator); JavascriptExecutor executor = (JavascriptExecutor) driver; executor.executeScript("arguments[0].click;", element); }

=Bearbeiten mit Alert und Frame=

In AWOB werden viele alert mit den Optionen "OK" und "Cancel" eingebaut. Um das Alert-Fenster zu behandeln, wird eine Method implementiert:

public static void handlingAlert(WebDriver driver){ Alert alert = driver.switchTo.alert; if (alert.getText.equals("alertText")) { alert.accept; }           else { alert.dismiss; }   }

In Selenium ist es auch möglich, dass der Wechsel zwischen Framefenster und Hauptfenster ausgeführt wird:

driver.switchTo.frame("framename"); driver.findElement(By.id("test")).click; driver.switchTo.defaultContent;

Wenn es kein Framename vorhanden ist, schreibt man dann:

driver.switchTo.frame(0); //1st frame without name

=Erstellung der Screenshots zur fehlgeschlagenen Tests=

Um fehlgeschlagene Tests durch Screenshots zu dokumentieren, kann eine Klasse "ScreenshotTestRule" implementiert werden:

class ScreenshotTestRule implements TestRule { public Statement apply(final Statement statement, final FrameworkMethod frameworkMethod, final Object o) { return new Statement { @Override public void evaluate throws Throwable { try { statement.evaluate; }                  catch (Throwable t){ captureScreenshot(frameworkMethod.getName); throw t; // rethrow to allow the failure to be reported to JUnit }               }                public void captureScreenshot(String fileName) { try { new File("target/surefire-reports/").mkdirs; // Insure directory is there FileOutputStream out = new FileOutputStream("target/surefire-reports/screenshot-" + fileName + ".png"); out.write(((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES)); out.close; } catch (Exception e) { // No need to crash the tests if the screenshot fails }               }            };         }     }

In der Tests-Klasse soll die Methode "ScreenshotTestRule" durch @Rule annotiert werden. @Rule public ScreenshotTestRule screenshotTestRule = new ScreenshotTestRule;

=Weitere Links:=

CSS Selektor Reference: http://www.w3schools.com/cssref/css_selectors.asp

Lokatoren in Selenium: http://docs.seleniumhq.org/docs/03_webdriver.jsp#locating-ui-elements-webelements

TestNG Dokumentation: http://testng.org/doc/documentation-main.html