Parallelisierung von Selenium-Tests mittels Sauce Labs

Quickstart
Voraussetzungen
– lauffähiges Maven: http://maven.apache.org
– Account bei SauceLabs: https://saucelabs.com/
1.) irgendwo den Ordner it-kosmopolit anlegen, darunter den Ordner src, darunter den Ordner test, darunter den Ordner java
2.) ParallelTest.java in it-kosmopolit\src\test\java legen (credentials im code anpassen, siehe unten)

package de.itkosmopolit.blog;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.By;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.annotations.Test;
import org.testng.Assert;
import java.net.URL;
import java.net.MalformedURLException;
public class ParallelTest {
    @Test
    public void parallel_with_firefox() throws MalformedURLException{
		//Konfigurationen
		DesiredCapabilities caps = DesiredCapabilities.firefox(); //Browser auswählen
        caps.setCapability("version", "13"); //Version des Browsers festlegen
        caps.setCapability("platform", "Linux"); //Betriebssystem festlegen
		caps.setCapability("name", "parallelTestFirefox"); //hier wird der Test benannt und in SauceLabs wieder auffindbar.
		caps.setCapability("username", "it-kosmopolit"); //Mein Username bei SauceLabs
		caps.setCapability("accessKey", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"); //Mein Access-key bei SauceLabs
        RemoteWebDriver driver = new RemoteWebDriver(
                new URL("http://it-kosmopolit:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx@ondemand.saucelabs.com:80/wd/hub"),
                caps);
		//Testcase
        driver.get("https://www.it-kosmopolit.de");
        driver.findElementByLinkText("KONTAKT UND ANGEBOT").click();
		WebElement profil = driver.findElement(By.partialLinkText("xing"));
		Assert.assertTrue(profil.getText().contains("Michael_Wowro"));
		//Beenden
        driver.quit();
    }
	 @Test
    public void parallel_with_internetExplorer() throws MalformedURLException {
	    //Konfigurationen
		DesiredCapabilities caps = DesiredCapabilities.internetExplorer(); //Browser auswählen
        caps.setCapability("version", "9"); //Version des Browsers festlegen
        caps.setCapability("platform", "Windows 2008"); //Betriebssystem festlegen
		caps.setCapability("name", "parallelTestInternetExplorer"); //hier wird der Test benannt und in SauceLabs wieder auffindbar.
		caps.setCapability("username", "it-kosmopolit"); //Mein Username bei SauceLabs
		caps.setCapability("accessKey", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"); //Mein Access-key bei SauceLabs
        RemoteWebDriver driver = new RemoteWebDriver(
                new URL("http://it-kosmopolit:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx@ondemand.saucelabs.com:80/wd/hub"),
                caps);
		//Testcase
        driver.get("https://www.it-kosmopolit.de");
        driver.findElementByLinkText("KONTAKT UND ANGEBOT").click();
		WebElement profil = driver.findElement(By.partialLinkText("xing"));
		Assert.assertTrue(profil.getText().contains("Michael_Wowro"));
		//Beenden
        driver.quit();
    }
}

3.) pom.xml in it-kosmopolit legen

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>de.itkosmopolit.blog</groupId>
    <artifactId>paralleltest</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>5.13.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium</artifactId>
            <version>2.0b1</version>
        </dependency>
	</dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <skip>true</skip>
					<parallel>methods</parallel>
					<threadCount>10</threadCount>
                </configuration>
                <executions>
                    <execution>
                        <phase>integration-test</phase>
                        <goals>
                            <goal>test</goal>
                        </goals>
                        <configuration>
                            <skip>false</skip>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

4.) in der DOS-Box in it-kosmopolit gehen und Folgendes ausführen: C:\“Program Files“\apache-maven-3.0.x\bin\mvn integration-test
Testcase
1.) Geh auf meinen Blog http://itkosmopolit.wordpress.com/
2.) Klicke dort auf den Link „KONTAKT UND ANGEBOT“
3.) Wenn der Link zum XING-Profil den Linktext „Michael_Wowro“ enthält, dann OK.
Story
Gerade wenn man die Funktionstests in seinen Continuous Integration einbinden will, jedoch auch, wenn man diese als Regressionstests vor jedem Release nutzt, kommt es auf die Durchführungsgeschwindigkeit der Tests an. Das Konzept schlechthin, die Funktionstests zu beschleunigen ist die Parallelisierung. Ich wähle für diesen Blogbeitrag Mozilla Firefox (auf Linux) und Internet Explorer (auf Windows) als Selenium Browser aus. Als Testframeworks werden in der Selenium-Community sowohl JUnit, als auch TestNG verwendet. TestNG erfreut sich jedoch größerer Beliebtheit (http://sauceio.com/index.php/2010/10/parallel-junit-4-and-selenium-part-one-parameters), weshalb ich es im Folgenden verwende. Für die Parallelisierung auf Methodenebene sorgt Maven und benötigt hierfür nur zwei Zeilen (siehe auch http://maven.apache.org/plugins/maven-surefire-plugin/examples/testng.html):

Das gleichzeitige Ausführen eines Selenium-Tests auf zwei verschiedenen Browsern (Parallelisierung) auf einem Rechner erweist sich als instabil. Manchmal funktioniert’s, manchmal gibt’s ein Unable to find element:

Diese Diskussion bestätigt dieses Phänomen: http://www.seleniumwebdriver.com/selenium-webdriver-developers/webdriver-directed-firefox-instances-fighting-each-other-on-the-same-machine/
Da ich mir das Aufsetzen eines Selenium Grids sparen möchte, gehe ich gleich zur Cloud-Lösung = Sauce Labs über: http://sauceio.com/index.php/tag/parallel-testing/ Voraussetzung ist hierfür natürlich ein Konto bei SauceLabs, welches jedoch einfach und ohne Verzögerung anzulegen ist. Für die Nutzung der SauceLabs API durch unser Testprogramm sind lediglich ein Username (wählt man selbst bei Anlegen des Kontos) und ein API-key (synonym: Access-key) nötig. Letzteren erzeugt SauceLabs automatisch und man kann diesen im Konto einsehen (und dort auch neu generieren lassen):
Dem besseren Verständnis geschuldet, baue ich das Testprogramm ohne Parametrisierung, also mit je einer eigenen Testmethode für den Firefox und einer für den Internet Explorer.
Die von SauceLabs angebotenen Browser-Betriebssystem-Kombis findet man hier: http://saucelabs.com/docs/ondemand/browsers – dort kann man auch direkt den Code für die gewünschte Programmiersprache generieren lassen. In diesem Blogbeitrag wird Java verwendet.
An dieser Stelle ist die SauceLabs-Doku etwas schlampig und die Eingabe der Credentials redundant. Neben der Verwendung des Usernames und des Access-Keys in der url, muss man diese auch noch in den capabilities aufrufen:

capabillities.setCapability("username", "it-kosmopolit");
capabillities.setCapability("accessKey", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
RemoteWebDriver driver = new RemoteWebDriver(
new URL("http://it-kosmopolit:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"@ondemand.saucelabs.com:80/wd/hub]]"),
capabillities);

Beachtet man dies nicht, wird man mit folgender Fehlermeldung „belohnt“:

"java.lang.UnsupportedOperationException: Unknown username.
You sent username 'None' in your browser string, which is not a valid Sauce Labs account."

Siehe auch: http://saucelabs.com/forums/viewtopic.php?id=509
Wenn alles gut geht, dann erscheint in der DOS-Box die Meldung mit Failures: 0 und Errors: 0

Unter myTests im SauceLab-Account kann man sich die (von mir erzeugten) Testergebnisse als Video und Log anschauen

Wenn man sich nun die Endzeiten (Finished) und die Laufzeit (Duration) anschaut, erkennt man die Parallelität der Testausführung. q.e.d.
Die Testreports habe ich auf public gesetzt – daher kann nun jeder, der die url kennt (=Datensicherheit) sich diese nun anschauen:
Internet Explorer
Firefox
Die Videos sind bedingt durch die Einfachheit der Testcases natürlich nicht besonders spektakulär – die Möglichkeiten, die damit gezeigt werden jedoch schon …
Spätestens, wenn man sich die Übersichtlichkeit der Testreports anschaut, erkennt man, dass die Jungs von SauceLabs einen tollen Job machen.