Im Blogbeitrag Parallelisierung von Selenium-Tests mittels Sauce Labs blieb ich noch eine skalierbare Parallelisierungslösung schuldig. TestNG bietet mit seinem DataProvider die Möglichkeit Parameter an seine Testmethoden zu übergeben (http://testng.org/doc/documentation-main.html#parameters-dataproviders). Dieses Tool möchte ich nun nutzen, um meinen Testmethoden zu sagen, welche Browser sie für meine Seleniumtests verwenden sollen. Als „Browserpark“ nutze ich wieder mal die Cloud der Sauce Labs Inc.
Den DataProvider kann man auch außerhalb der Testklasse speichern und dann in jede Testklasse integrieren. Meist sind bei den Funktionstests zahlreiche Testklassen im Spiel. Da ich nicht bei jedem major release von Firefox und Konsorten in jede Testklasse einzeln gehen möchte, um diesen dort hinzuzufügen, drängt sich Auslagerung des DataProviders in eine eigene .class geradezu auf.
Die verwendeten Browser sind:
- Firefox, Version 12, Linux
- Internet Explorer, Version 9, Windows Vista
- Chrome, Version von Sauce Labs bestimmt, Windows Vista
- Safari, Version 5, Mac
Ich verwende im Beispiel also zwei Testklassen namens Parallel1Test.java und Parallel2Test.java, sowie eine Klasse worin ich den DataProvider auslagere, die ich, angelehnt an einen Fuhrpark, mit BrowserPark.java bezeichne.
Parallel1Test.java
import java.net.MalformedURLException; import java.net.URL; import java.util.concurrent.TimeUnit; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; import org.testng.Assert; import org.testng.annotations.Test; public class Parallel1Test { @Test(description = "Testet Erreichbarkeit meiner Angebotsseite.", dataProvider = "BrowserPark", dataProviderClass = BrowserPark.class) public void paralleltest1(URL url, DesiredCapabilities caps) throws MalformedURLException, InterruptedException { //Konfigurationen caps.setCapability("name", "paralleltest1: check Michael Wowro"); WebDriver driver; if (BrowserPark.isDevelopedLocal) driver = new FirefoxDriver(caps); else driver = new RemoteWebDriver(url, caps); driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); //Testcase driver.get("https://www.it-kosmopolit.de"); driver.findElement(By.linkText("KONTAKT UND ANGEBOT")).click(); WebElement profil = driver.findElement(By.partialLinkText("xing")); Assert.assertTrue(profil.getText().contains("Michael_Wowro")); //Beenden driver.quit(); } }Parallel2Test.java
import java.net.MalformedURLException; import java.net.URL; import java.util.concurrent.TimeUnit; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; import org.testng.Assert; import org.testng.annotations.Test; public class Parallel2Test { @Test(description = "Testet Erreichbarkeit meiner Angebotsseite.", dataProvider = "BrowserPark", dataProviderClass = BrowserPark.class) public void paralleltest2(URL url, DesiredCapabilities caps) throws MalformedURLException, InterruptedException { //KonfigurationeN caps.setCapability("name", "paralleltest2: check xing"); WebDriver driver; if (BrowserPark.isDevelopedLocal) driver = new FirefoxDriver(caps); else driver = new RemoteWebDriver(url, caps); driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); //Testcase driver.get("https://www.it-kosmopolit.de"); driver.findElement(By.linkText("KONTAKT UND ANGEBOT")).click(); WebElement profil = driver.findElement(By.partialLinkText("xing")); Assert.assertTrue(profil.getText().contains("xing")); //Beenden driver.quit(); } }browserPark.java
import java.net.MalformedURLException; import java.net.URL; import org.openqa.selenium.remote.DesiredCapabilities; import org.testng.annotations.DataProvider; // Übersicht über Browser-Angebot bei Sauce Labs: https://saucelabs.com/docs/browsers public class BrowserPark { static boolean isDevelopedLocal; static String username = "it-kosmopolit"; static String accessKey = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; static String url = "http://" + username + ":" + accessKey + "@ondemand.saucelabs.com:80/wd/hub"; // /* Entwicklung gegen meinen lokalen Firefox-Browser */ // @DataProvider(name = "BrowserPark") // public static Object[][] developLocal() throws MalformedURLException { // isDevelopedLocal = true; // DesiredCapabilities capFF = DesiredCapabilities.firefox(); //Browserdefaults auswählen // // return new Object[][]{ // {new URL("http://www.egal.de"), capFF} // }; // } // /* Entwicklung gegen einen ausgesuchten Browser in der Sauce Labs-Cloud */ // @DataProvider(name = "BrowserPark") // public static Object[][] developRemote() throws MalformedURLException { // isDevelopedLocal = false; // // // FF // DesiredCapabilities capFF = DesiredCapabilities.firefox(); //Browserdefaults auswählen // capFF.setCapability("version", "12"); //Version des Browsers festlegen // capFF.setCapability("platform", "Linux"); //Betriebssystem festlegen // capFF.setCapability("username", username); //Mein Username bei SauceLabs // capFF.setCapability("accessKey", accessKey); //Mein Access-key bei SauceLabs // // return new Object[][]{ // {new URL(url), capFF} // }; // } /* Produktivmodus mit den von meinen Kunden gewünschten Browser-Betriebssystem Kombinationen */ @DataProvider(name = "BrowserPark") public static Object[][] productive() throws MalformedURLException { isDevelopedLocal = false; // FF DesiredCapabilities capFF = DesiredCapabilities.firefox(); //Browserdefaults auswählen capFF.setCapability("version", "12"); //Version des Browsers festlegen capFF.setCapability("platform", "Linux"); //Betriebssystem festlegen capFF.setCapability("username", username); //Mein Username bei SauceLabs capFF.setCapability("accessKey", accessKey); //Mein Access-key bei SauceLabs // IE DesiredCapabilities capIE = DesiredCapabilities.internetExplorer(); //Browserdefaults auswählen capIE.setCapability("version", "9"); //Version des Browsers festlegen capIE.setCapability("platform", "Windows 2008"); //Betriebssystem festlegen capIE.setCapability("username", username); //Mein Username bei SauceLabs capIE.setCapability("accessKey", accessKey); //Mein Access-key bei SauceLab //Chrome DesiredCapabilities capCH = DesiredCapabilities.chrome(); //Browserdefaults auswählen capCH.setCapability("platform", "Windows 2008"); //Betriebssystem festlegen capCH.setCapability("username", username); //Mein Username bei SauceLabs capCH.setCapability("accessKey", accessKey); //Mein Access-key bei SauceLab //Safari DesiredCapabilities capSA = DesiredCapabilities.safari(); //Browserdefaults auswählen capSA.setCapability("version", "5");//Version des Browsers festlegen capSA.setCapability("platform", "Mac 10.6");//Betriebssystem festlegen capSA.setCapability("username", username); //Mein Username bei SauceLabs capSA.setCapability("accessKey", accessKey); //Mein Access-key bei SauceLab return new Object[][]{ {new URL (url), capFF}, {new URL (url), capIE}, {new URL (url), capCH}, {new URL (url), capSA} }; } }Wie im Code zu sehen, habe ich drei Versionen des DataProviders:
- zum Entwickeln der Tests gegen meinen aktuell lokal installierten Firefox
- zum Entwickeln der Tests gegen einen ausgewählten Browser in der Sauce Labs-Cloud
- und den vom Kunden gewünschten Browserpark, gegen den seine Internet-Anwendung getestet wird (sozusagen der Produktivmodus). Und hier kann man sich die Browser-Betriebssystem-Kombinationen für seinen individuellen Browserpark zusammenstellen: https://saucelabs.com/docs/browsers
Die beiden Versionen, die ich gerade nicht nutzen möchte, schalte ich einfach per Auskommentieren aus.
Alle 3 Klassen liegen in meiner Maven-Verzeichnisstruktur \src\test\java. Ein entsprechendes Maven-Projekt habe ich in netbeans angelegt. Ein Click auf „test“ und nachdem mir netbeans den erfolgreichen Testlauf bestätigt, gehe ich in mein Sauce Labs-Konto um mir die Schätzchen anzuschauen. Und siehe da, für jeden meiner vier verschiedenen Browser sind je beide Tests erfolgreich durchgelaufen:
Hinweis: Da das für diesen Blogpost verwendete Sauce Labs-Konto auf zwei Threads beschränkt ist, sind in diesem Beispiel immer nur zwei Testläufe parallel.
Weil ich es richtig gut finde, dass Sauce Labs von jedem meiner Testläufe ein Video aufzeichnet, schau ich mir eins auch noch mal an: