ROI der Testautomatisierung

Es gibt zwei grundsätzliche Herangehensweisen eine Internet-Anwendung zu testen: manuell oder automatisch. Da die Internet-Anwendungen immer umfangreicher und komplexer werden, gleichzeitig aber auch die Testautomatisierungslösungen immer raffinierter werden, lohnt sich für jeden IT-Entscheider die Beschäftigung mit dem Thema Return On Investment (ROI) der Testautomatisierung.
Grundsätzlich gibt es drei Kriterien, die Einfluss auf die Rentabilität der Testautomatisierung haben: Stabilität des Testobjektes (wird der darunterliegende Code oft oder selten geändert?), Häufigkeit der Testausführung (bei Continous Integration findet die Testausführung mindestens täglich statt) und Kritikalität des Testobjektes (wie kritisch wäre es, wenn bei einem manuellen Test ein Bug übersehen wird). Das Software Quality Lab hat dies hier (Seite 3) weiter ausgeführt.
Der ROI wird berechnet aus dem Gesamtnutzen der Testautomatisierung / Gesamtkosten der Testautomatisierung.
Die Gesamtkosten der Testautomatisierung sind mit Selenium WebDriver relativ schnell skizzierbar.
1.) Die Testautomatisierungslösung Selenium WebDriver ist Open Source und damit kostenlos (siehe auch meinen letzten Blogpost Selenium ist und bleibt Open Source.
2.) Infrastrukturinvestitionen sind ebenfalls nicht nötig – also insbesondere muss keine Hardware angeschafft werden und auch kein Experte für die Installation von diversen Programmsuiten angeheuert werden. Es gibt nämlich bereits zuverlässige Cloudanbieter, die die komplette benötigte Infrastruktur zur Verfügung stellen und (all-inclusive warten), beispielsweise http://www.cloudbees.com. Selbst deren Enterprise-Variante kostet monatlich lediglich $100 und darin sind knapp 7 Tage Laufzeit/Monat inklusive, was für die meisten Internetanwendungen bei Weitem ausreichen sollte. In der Kostenlos-Variante sind 5 Stunden Laufzeit / Monat inklusive, was bereits für einen Proof of Concepts genügt.
3.) Bleiben lediglich noch die Kosten für einen auf Selenium spezialisierten Test Automation Engineer. Da produktives Arbeiten mit einer Testautomatisierungslösung generell einiges an Knowhow und Erfahrung erfordert, ist es empfehlenswert sich einen Experten ins Boot zu holen – zumindest für die initiale Testautomatisierungs-Phase. Ich kenne wenige Bereiche in der IT, die besser für Outtasking und Remote-Working geeignet wären, als der Bereich Testautomatisierung. Fallen also keine Hotel-, Bewirtungs- und Reisekosten an, die klassische On-site-Freelancer natürlich in Ihre Stundensätze einkalkulieren müssen – auch muss kein Arbeitsplatz zur Verfügung gestellt werden. Ebenso fallen keine Mitarbeiternebenkosten an – wobei es ohnehin fraglich ist, ob sich kleinere Projekte/Unternehmen/Abteilungen einen „ganzen“ Test Automation Engineer leisten möchten. Schreiben Sie mir einfach eine E-Mail, was eine Test Automation Engineer-Stunde bei IT Kosmopolit kostet und Sie werden sicher positiv überrascht sein.
Beim Gesamtnutzen der Testautomatisierung wiegt v.a. der Wegfall der unzähligen manuellen Teststunden. Kalkulieren Sie hierbei jedoch nicht nur die Stunden der offiziellen Tester ein, sondern auch die der Entwickler und anderen Mitarbeiter, die ebenfalls (inoffiziell) mittesten.
Natürlich ermüden manuelle Tester mit der Zeit durch ihre monotone Tätigkeit und natürlich können beim manuellen Testen nicht annähernd so viele Testfälle akkurat durchgetestet werden, wie das bei einer Testautomatisierungslösung der Fall ist. Testautomatisierung sorgt damit nachhaltig für eine gesteigerte Softwarequalität. Beispielsweise kann ich mit Selenium mit wenigen Handgriffen den aktuellen Chrome und den aktuellen Firefox in die Testsuite hinzuschalten, dann werden alle Testfälle automatisch und ohne weiteres Zutun komplett auch für diese Browser durchgetestet.
Natürlich testet Selenium wesentlich schneller als sein menschlicher Kollege und auch gerne nachts oder am Wochenende – dadurch ist die Time-To-Market neuer Features deutlich verkürzt.
Moderne Softwareentwicklungsmethoden (Agile Development, wie bsp.weise SCRUM) werden schließlich durch Testautomatisierung überhaupt erst möglich.
Das folgende Diagramm zeigt die Kostenentwicklung des manuellen Testens im Vergleich zur Testautomatisierung eines nicht untypischen Projektverlaufs.

Der rote Kurvenverlauf der monatlichen Kosten (manuelles Testen): Die Kosten fallen mit Projektbeginn an, auch wenn hierfür nicht immer ein Kostenbewusstsein bei den Verantwortlichen besteht. Der Verlauf ist konstant steigend, da die Anzahl der Features und die Komplexität der Internetanwendung kontinuierlich steigt und damit auch die Anzahl der Testfälle und der Umfang der manuellen Tests.
Der grüne Kurvenverlauf der monatlichen Kosten (automatisches Testen): Den manuellen Kosten werden als Alternative die Kosten automatischen Testens gegenübergestellt. Nicht selten entsteht das Kostenbewusstsein bzgl. des Testaufwands bei den Verantwortlichen erst nach gewisser Zeit. Darum wurde der Beginn der Testautomatisierung in diesem Diagramm auf den Anfang des zweiten Jahres gelegt. (Klar, dass die konsequente Testautomatisierung bereits zu Projektbeginn Kostenvorteile gegenüber dem manuellen Testen hat.) Zwei kostenreiche Monate im Zuge der Automatisierung aller bis dahin spezifizierten Testfälle. Danach die konstant niedrigen Kosten für die Pflege der bestehenden Testprogramme und die Erweiterung der Testsuite um neue Features.
Die gelbe Kurve zeigt schließlich den Gesamt-ROI eines Umstiegs von manuellem Testen hin zu automatisiertem Testen – ein deutlicher Anstieg – Ihr Gewinn!
Weitere, wissenschaftliche Artikel zu diesem Thema:
1.) Software Test Automation in Practice: Empirical Observations
2.) Veröffentlichungsliste von Jussi Pekka Kasurinen

Selenium ist und bleibt Open Source

… und damit kostenlos. Simon Stewart, Software Engineer in Test bei Google und Chefentwickler von Selenium Webdriver (dem Nachfolger von Selenium RC) hat sich heute dazu bekannt, dass Selenium Open Source bleiben wird, so lange er das Sagen hat. Dies ist für den zukünftigen Erfolg des Selenium-Projekts eine zentrale Aussage. Nun gibt es in puncto Investitionssicherheit quasi eine langfristige Garantie für Unternehmen, die auf Selenium zur Testautomatisierung ihrer Internetanwendung setzen. Weiterhin dürfte diese Festlegung den Abstand zum Hauptkonkurrenten HP Unified Functional Testing (ehemals QTP, proprietär) vergrößern. Eine offizielle Ausweisung der Lizenzkosten seitens HP ist im Netz nicht zu finden. Hier finden Sie den kompletten Thread in Selenium Users: https://groups.google.com/forum/?fromgroups=#!topic/selenium-users/7zIYjJaVgOY

Email-Korrespondenz in Selenium integrieren

Das häufigste Testszenario, in dem Emails integriert sind, ist der Registrierungsvorgang bei einer Internet-Anwendung. Nachdem der neue User das Kontaktdatenformular ausgefüllt und abgeschickt hat, bekommt er eine Email in die Mailbox, welche ein Sicherheitsmerkmal (Link, Passwort) enthält, dessen Benutzung die Registrierung erfolgreich abschließt.
Nun ist der Einsatz von Selenium weitgehend auf die Reichweite des Browsers beschränkt, will sagen, dass man nicht ohne andere Tools und Aufwand auf Mailclients (Outlook, Thunderbird, …) bei der Automatisierung der Tests zurückgreifen kann. Es gibt jedoch die Möglichkeit sich eines Webmail-Clients zu bedienen, der eine Administrationsoberfläche für Emails darstellt, die vollständig innerhalb eines Browsers bedient werden kann. Den Ansatz über einen Instant-Email-Dienst (spambog.com, instant-mail.de, …) zu gehen, empfehle ich für den produktiven Testeinsatz nicht, da diese im Emailempfang mindestens verzögert, wenn nicht gar gänzlich unzuverlässig sind. So hatte beispielsweise spambog.de bei einem Einsatz eine Verzögerung von genau einer Stunde. Bei meinem aktuellen Auftrag: www.hiorg-server.de wird ausdrücklich von der Nutzung von den bekannten Mailprovidern (web.de, hotmail.de, …) abgeraten, da manche Funktionen des hiorg-server.de dort als Spam gewertet werden (natürlich ohne es zu sein), weshalb diese Möglichkeit auch wegfällt. Ich nehme mal an, dass die meisten Tester mindestens einen Webspace mit eigener Domain und angeschlossenem Webmail-Client besitzen. Dies ist für den Standardgebrauch in Selenium ausreichend. Ich benutze für diesen Artikel Atmail, weshalb auch meine WebMail-Klasse auf diesen WebMailer ausgerichtet ist.
Die Auslagerung der Emailfunktionen in eine separate Mail-Klasse entspricht der Anforderung des Page Object Patterns, dass man die Navigation beliebig umbauen kann, ohne jedoch die Testklassen selbst ändern zu müssen. Dieses Design schließt auch ein, dass der domain part der Email-Adresse (wiki) nicht in der Testklasse auftaucht. Diese Testklasse kenne nur die Methoden der Mail-Klasse, ohne ihre Implementierungsdetails, also in unserem Fall:
new WebMail().getRegistrationText(String keywordInSubject, boolean löscheEmail)
1.) Das keywordInSubject ist notwendig, um die Email meines Threads eindeutig in meiner Mailbox zu identifizieren. Bei paralleler Ausführung unterschiedlicher Testcases (mit Email-Beteiligung) kann man naturgemäß als Tester nicht die Reihenfolge vorausahnen, wann welcher Thread die Mailbox erreicht, um dort „seine“ Email abzuholen. Hier entsteht also eine Race-Condition zwischen den parallel getesteten Testcases. Logiken, wie „nimm die erste Email in der Mailbox“ scheiden daher aus. Wir benötigen eine Möglichkeit wie der Thread „seine“ Email erkennt, diese also eindeutig in der Mailbox unterscheidbar ist.
2.) mit boolean löscheEmail kann ich mich entscheiden, ob nach der Prüfung die Registriermail gelöscht werden kann, um unseren Stall sauber zu halten…
Und hier der Code:
EmailTest.java

package de.hiorgserver.testhiorgserver;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.Assert;
import org.testng.annotations.Test;
public class EmailTest {
    @Test
    public void testEmail() throws MalformedURLException, InterruptedException {
        String username = "cloudbees_it-kosmopo";
        String accessKey = "XXX";
        String url = "http://" + username + ":" + accessKey + "@ondemand.saucelabs.com:80/wd/hub";
        DesiredCapabilities cap = DesiredCapabilities.firefox(); //Browserdefaults auswählen
        cap.setCapability("version", "15"); //Version des Browsers festlegen
        cap.setCapability("platform", "Windows 2008"); //Betriebssystem festlegen
        cap.setCapability("username", username); //Mein Username bei SauceLabs
        cap.setCapability("accessKey", accessKey); //Mein Access-key bei SauceLabs
        WebDriver driver = new RemoteWebDriver(new URL(url),cap);
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        WebMail webmailer = new WebMail(driver, "test");
        String emailText = webmailer.getRegistrationText("mein Blog", true);
        Assert.assertTrue(emailText.contains("Benutzerkonto"), "Prüfung, ob der Registrierungstext das Schlüsselwort 'Benutzerkono' enthält.");
        driver.quit();
    }
}

WebMail.java

package de.hiorgserver.testhiorgserver;
import java.util.List;
import java.util.Set;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.interactions.Actions;
public class WebMail {
    WebDriver driver;
    String mainWindow;
    WebMail (WebDriver driver,String localPart) {
        this.driver = driver;
        String url = "http://webmail.it-kosmopolit.de/";
        String password = "XXX";
        //Öffne ein neues Fenster, dann kann ich es zwischendurch immer wieder verwenden.
        mainWindow = driver.getWindowHandle();
        JavascriptExecutor js = (JavascriptExecutor) driver;
        js.executeScript("window.open('','Email-Fenster')");
        driver.switchTo().window("Email-Fenster");
        driver.get(url);
        driver.switchTo().frame("GroupingFrame");
        driver.findElement(By.id("username")).sendKeys(localPart);
        driver.findElement(By.id("password")).sendKeys(password);
        driver.findElement(By.name("Submit")).click();
    }
    String getRegistrationText(String keywordInSubject, boolean löscheEmail) throws InterruptedException {
        if ( ! driver.getCurrentUrl().contains("http://webmailtest.it-kosmopolit.de")) driver.switchTo().window("Email-Fenster") ;
        Thread.sleep(2000); //nur für's Schauvideo angehalten.
        Actions action = new Actions(driver);
        action.doubleClick(driver.findElement(By.xpath("//*[contains(text(),'" + keywordInSubject + "')]")));
        action.perform();
        Thread.sleep(2000); //nur für's Schauvideo angehalten.
        driver.switchTo().frame("msgwindow1");
        String link = driver.findElement(By.xpath("//*[contains(text(),'Registrierung')]")).getText();
        if (löscheEmail) {
            driver.switchTo().defaultContent();
            driver.findElement(By.id("Folderdelete")).click();
        }
        Thread.sleep(2000); //nur für's Schauvideo angehalten.
        driver.get(link);
        Thread.sleep(2000); //nur für's Schauvideo angehalten.
        String text = driver.findElement(By.tagName("body")).getText();
        driver.switchTo().window(mainWindow);
        return text;
    }
}

Und hier der Testverlauf samt Video: https://saucelabs.com/tests/5e80dba5bfe74327aa68aaaefaa08737#
Hinweis: der Test würde noch schneller laufen, wenn ich nicht den Thread mehrmals schlafen gelegt hätte, damit der Programmverlauf im Video leichter nachvollzogen werden kann.
„Verschärfte“ Testbedingungen
Die Internetanwendung kann erzwingen, dass die Email-Adressen innerhalb der Internet-Anwendung eindeutig sein müssen. Dies ist beispielsweise dann der Fall, wenn die Email gleichzeitig die Bezeichnung des Users ist. Wenn ich nun gegen eine Testmaschine teste, habe ich bei einer hartcodierten Emailadresse nur einen Test frei. Jeden wiederholten/parallelen Testdurchlauf wird mir die Testumgebung quittieren mit: „Ihre Email-Adresse ist bereits vergeben“. Dann müsste theoretisch jedes Mal die Datenbasis der Testumgebung auf den „Zeitpunkt 0“ zurückgestellt werden – ein hoher manueller Aufwand!
Einen Lösungsansatz für diese verschärften Testbedingungen möchte ich an dieser Stelle nur mal skizzieren:

  1. Neuen Webspace incl. Domain erstellen
  2. als local part (wiki) einen Timestamp (natürlich nur erlaubte Zeichen) nehmen. Durch den (Millisekunden-genauen) Timestamp ist mit hoher Wahrscheinlichkeit die verwendete Email-Adresse unique. Anhand des Empfängers kann man die Emails im Webmail-Client also eindeutig identifizieren.
  3. Forward mail of non-existent user to following-default Emailadresse: test@neuedomain.de
  4. test@neuedomain.de per Webmail-client aufrufen