Appium – Eine Einführung (Teil 1)

In den folgenden drei Blogartikeln möchte ich Ihnen Appium vorstellen: Ein Testautomatisierungs-Tool, welches speziell für den Test mobiler Anwendungen entwickelt wurde. Appium bietet uns die Möglichkeit, mobile-spezifische Anwendungsfälle wie z. B. Gestensteuerung, SMS oder eingehende Anrufe zu simulieren und entsprechende Testfälle zu automatisieren. Neben virtuellen Geräten bietet uns Appium als zusätzliches Feature die Möglichkeit, automatisierte Testfälle auf realen mobilen Endgeräten auszuführen.

Wieso auf mobilen Geräten automatisieren?

Aber wieso sollten wir unsere Testautomatisierung auf realen Endgeräten ausführen? Wieso sollten wir nicht die virtuellen Geräte der Entwicklungstools Xcode (iOS) und Android Studio (Android) nutzen? Dies sind berechtigte Fragen, denn die Anschaffung von Endgeräten verursacht Kosten.

Das erste Argument für eine Automatisierung auf realen Endgeräten mag banal klingen, fällt jedoch schwer ins Gewicht: Ihre Anwenderinnen und Anwender nutzen keine virtuellen Geräte.

Man könnte annehmen, dass virtuelle Geräte reale Endgeräte eins zu eins widerspiegeln. Diese Annahme ist jedoch falsch. Der Hauptgrund dafür ist, dass virtuelle Geräte keine eigene Hardware besitzen. Sie nutzen die Hardware des Rechners, auf dem sie installiert sind. Die Erfahrung zeigt auch, dass Fehler, die auf einem realen Endgerät entdeckt wurden, in virtuellen Geräten nicht immer zuverlässig reproduziert werden können.

Das Automatisieren auf realen Endgeräten ermöglicht Ihnen außerdem, die Performance Ihrer Anwendung zu überprüfen. Selbst wenn alle Funktionen in Ihrer Anwendung einwandfrei funktionieren, kann eine schlechte Performance auf dem Endgerät dazu führen, dass Ihre Anwendung unbrauchbar ist. Tests auf virtuellen Geräten liefern uns diesbezüglich keine verlässlichen Daten.

Auch das Problem der Hardware- und Software-Fragmentierung ist als ein Argument für die Automatisierung auf realen Endgeräten zu verstehen.

Sowohl bei iOS- als auch bei Android-Geräten entsteht durch immer größere Produktpaletten sowie Betriebssystemversionen, die immer länger im Umlauf bleiben, eine Art natürliche Fragmentierung – wie die folgenden Statistiken zeigen.

iOS Verteilung auf Apple-Geräten - Q2 2020
Abbildung 1: iOS Verteilung auf Apple-Geräten – Q2 2020 | https://developer.apple.com/support/app-store/
Android OS Verteilung - Q2 2020
Abbildung 2: Android OS Verteilung – Q2 2020 | https://9to5google.com/2020/04/10/google-kills-android-distribution-numbers-web

Bei Android-Geräten können wir eine weitere Software-Fragmentierung beobachten. Den Herstellern ist es möglich, das Android-Betriebssystem in einem gewissen Rahmen zu verändern. So können System-Apps wie die virtuelle Tastatur unterschiedlich funktionieren.

Nehmen wir als Beispiel das Gboard von Google und die virtuelle Tastatur OneU von Samsung. Beide unterstützen Swipe-Steuerelemente oder die Eingabe von Gesten, unterscheiden sich jedoch in der Ausführung.

Googles virtuelle Tastatur zeigt Ihnen das Wort, das gebildet wird, wenn Sie über die Tastatur gleiten. Samsungs Tastatur hingegen zeigt Ihnen das Wort erst, wenn Ihre Finger nicht mehr gleiten. Man sollte nicht davon ausgehen, dass die virtuellen Geräte von xCode oder Android Studio diese Unterschiede simulieren.

Natürlich können wir keinen unendlich großen Pool mit mobilen Endgeräten aufbauen. Wir können jedoch eine Auswahl von Geräten treffen, die bei Ihren Anwenderinnen und Anwendern stark vertreten sind.

Endgeräte von Apple, Samsung und Huawei sind sicher entscheidender für einen Endgeräte-Pool als Geräte anderer Hersteller, wie die folgenden Statistiken zeigen.

Hersteller Marktanteile Deutschland Q2 2020
Abbildung 3: Hersteller Marktanteile Deutschland Q2 2020 | de.statista.com
Hersteller Marktanteile USA Q2 2020
Abbildung 4: Hersteller Marktanteile USA Q2 2020 | https://www.canalys.com/newsroom/canalys-us-smartphones-shipments-Q2-2020

Problematik – Testautomation Tool-Fragmentierung

Nachdem ich nun auf die Vorteile der Testautomatisierung auf realen Endgeräten eingegangen bin, stellt sich natürlich noch immer die grundsätzliche Frage für Projekte mit einer vorhandenen Testautomatisierung: Wieso sollte Appium als zusätzliches Testautomatisierungstool eingeführt werden?

Das Problem der Software-Fragmentierung lässt sich auch in der Testfallautomatisierung beobachten. Es gibt immer mehr Tools, die bestimmte Funktionen und Umgebungen unterstützen, untereinander jedoch nur bedingt kompatibel sind. Im Idealfall wollen wir aber nur ein einziges Testautomatisierungstool nutzen, um die Hürden in der Testfallautomatisierung gering zu halten.

Um die zuletzt gestellte Frage zu klären, lassen Sie uns von einem Multiplattformprojekt ausgehen.

Unsere Anwendung wurde als Desktop-Webseite, native iOS-App und hybride Android-App programmiert. Zusätzlich haben wir eine responsive Web-App erstellt, denn Ihre Webseite besitzt bereits eine gute Abdeckung an automatisierten Testfällen durch Selenium.

Die folgenden Statistiken zeigen, dass eine Testfallautomatisierung, welche sich lediglich auf die Webseite beschränkt, für unser Multiplattformprojekt nicht mehr ausreicht.

Besitz und Nutzung von Smartphones nach Altersgruppen in Deutschland 2019
Abbildung 5: Besitz und Nutzung von Smartphones nach Altersgruppen in Deutschland 2019 | de.statista.com
Umsatz Mobile Stores in Mrd. US$
Abbildung 6: Umsatz Mobile Stores in Mrd. US$ | https://sensortower.com/blog/app-revenue-and-downloads-1h-2020

Wir sollten davon ausgehen, dass alle relevanten Zielgruppen unsere Anwendung auch auf mobilen Endgeräten nutzen.

Appium vs. Selenium

Ein kurzer Blick zurück auf die Ursprünge der Testautomatisierungstools zeigt, wieso die Einführung von weiteren Tools in unserem Beispiel sinnvoll ist.

Die ersten Applikationen, für die Testfälle auf Endgeräten automatisiert wurden, waren unter anderem Webseiten. Durch das Aufkommen von immer mehr Browsern wurde eine Automatisierung von Testfällen auch im Frontendbereich notwendig.

Eines der erfolgreichsten Testautomatisierungs-Tools in diesem Bereich ist Selenium. Den Ursprüngen entsprechend ist Selenium allerdings auf die Testfallautomatisierung von Webseiten ausgerichtet. Mobile spezifische Anwendungsfälle wie Gestensteuerung werden ohne Weiteres nicht unterstützt.

Doch gehen wir in unserem Multiplattformprojekt einmal davon aus, dass nur ein kleiner Teil der User die mobilen Anwendungen nutzt. Der Großteil nutzt die Desktop-Webseite und diese besitzt, wie wir wissen, eine gute automatisierte Testfallabdeckung durch Selenium. Lohnt sich dennoch die Einführung von Appium?

Nachdem ich das Problem der Tool-Fragmentierung kurz erläutert habe, wäre die Einführung von Appium eventuell mit mehr Kosten als Nutzen verbunden. Man könnte annehmen, unsere in der Selenium-Automatisierung erfahrenen Teams können die wichtigsten Testfälle mit Selenium und ein paar Workarounds für unsere mobilen Anwendungen automatisieren. Doch schauen wir uns Appium etwas genauer an, um zu überprüfen, ob diese Behauptung zutrifft.

Automatisierung mobile-spezifischer Anwendungsfälle mit Appium

Gehen wir zunächst auf die Problematik der mobile-spezifischen Anwendungsfälle ein. Lassen Sie uns einen Blick auf einige Anwendungsfälle werfen, die Appium unterstützt, bei denen sich für unsere Experten für Testautomatisierung mit Selenium sicher schnell Hürden aufbauen.

Gestensteuerung

In unserer Anwendung existiert eine Liste, deren Ende unsere Benutzerinnen und Benutzer gerne erreichen würde. In der Desktop-Browser-Version nutzen die User dafür sicher das Mausrad, den Scrollbalken oder die Pfeiltasten auf der Tastatur. In den mobilen Anwendungen werden sie allerdings auf diverse Gesten zurückgreifen, um das Ende der Liste zu erreichen.

Sie könnten den Finger auf den unteren Bildschirmbereich setzen, ihn halten, nach oben ziehen und wieder lösen, um nur einen bestimmten Teil der Liste zu bewegen. Eine weitere Möglichkeit wäre, den Finger auf den unteren Bildschirmrand zu setzen und mit einer schnellen Wischgeste nach oben ein automatisches Scrollen nach unten auszulösen. Für diese Fälle können wir auf die TouchAPI von Appium zurückgreifen.

Anrufe und SMS

Eingehende Anrufe und SMS wirken sich auf mobilen Endgeräten viel schwerer auf die Nutzung unserer Anwendung aus. Wo sich auf dem Desktop bei einem Anruf meistens nur ein weiteres Fenster öffnet, wird auf mobilen Endgeräten die laufende Anwendung meist unterbrochen und die jeweilige Anwendung für Telefonanrufe in den Vordergrund geholt. Auch eingehende SMS lösen meist eine Benachrichtigung über der laufenden Anwendung aus. Für diese Fälle können wir auf die Phone-Call-API von Appium zurückgreifen.

Systemanwendungen

Auf mobilen Endgeräten kommt unsere Anwendung wahrscheinlich viel häufiger in Verbindung mit Systemanwendungen. Sei es der Kalender, die Fotogalerie oder die hauseigene Kartenanwendung. Appium bietet uns an dieser Stelle – abhängig davon, welchen Appium Driver wir nutzen – die Möglichkeit diese Systemanwendungen ebenfalls in unsere Testautomatisierung zu integrieren.

Automatisierung von hybriden Apps

Betrachten wir nun die Problematik der Tool-Fragmentierung in der Testfallautomatisierung. Ein Teil des Problems besteht in den verschiedenen Entwicklungsarten von mobilen Applikationen. In unserem Beispielprojekt sind die üblichen Arten vertreten.

Werfen wir einen genaueren Blick darauf, wie Appium mittels der Context API, mit den komplexeren hybriden Anwendungen umgeht.

Um Elemente zu finden oder mit ihnen zu interagieren, geht Appium standardmäßig davon aus, dass sich all unsere Befehle auf native UI-Komponenten beziehen, die auf dem Bildschirm angezeigt werden. Unsere Testsession befindet sich also noch im sogenannten Native Context.

Nutzen wir z. B. den Appium-Befehl getPageSource im Rahmen einer hybriden Anwendung, werden wir in der Ausgabe bezüglich der Web Views nur Elemente finden wie <XCUIElementType…>. Wichtige Elemente wie Anchor Tags oder Divs werden uns zunächst nicht angezeigt.

Solange wir uns also im Native Context bewegen, sind alle Web Views oder sogenannter Web Context eine Blackbox für Appium. Wir sind zwar in der Lage, Web View UI-Elemente auszumachen und eventuell auch einige Buttons, die zum Beispiel iOS mit sich bringt. Elemente anhand von CSS-Selektoren auszumachen, wird jedoch nicht möglich sein.

Um besseren Zugriff auf den Web Context zu bekommen, müssen wir unsere Appium Session in den Web Context bringen. Dies können wir tun, indem wir zunächst den Namen des Web Contexts mit dem Befehl driver.getContextHandles ausmachen. Dieser gibt ein Array aller Context-Namen zurück, die Appium erstellt hat, um sie dem verfügbaren Context zuzuordnen. In unserem Fall wird uns ein Web Context namens WebView1 und ein Native Context namens NativeElement1 ausgegeben.

Um unsere Appium Session nun in den Web Context zu bringen, nutzen wir den Befehl driver.setContext(WebView1). Wenn dieser Befehl ausgeführt wurde, nutzt Appium die Context-Umgebung, die dem angegebenen Context entspricht.

Alle weiteren Befehle operieren nun innerhalb des Web Context und beziehen sich auf WebView1. Um wieder das native Element ansprechen zu können, nutzen wir den gleichen Befehl erneut mit dem Namen des Native Context, den wir ansprechen wollen. In unserem Fall also driver.setContext(NativeElement1). Wenn wir herausfinden möchten, in welchem Context wir uns aktuell befinden, können wir den folgenden Befehl nutzen: String currentContext = driver.getContext();

Nachdem wir nun kurz auf die Context API von Appium eingegangen sind, lassen Sie uns einen Blick auf die Funktionsweise werfen.

Auf iOS nutzt Appium das sogenannte „remote Debugger Protocol“, welches von Safari unterstützt wird. Dieses „remote Debugger Protocol“ ermöglicht es uns, Information über die in Safari angezeigten Seiten zu erhalten oder das Browserverhalten zu kontrollieren. Eine Methode, auf die wir zurückgreifen können, ist die Möglichkeit, JavaScript in die aktuelle Webseite einzufügen.

Appium verwendet diese Funktion, um alle in der WebDriver API verfügbaren Befehle durchzuführen.

Unterstützung von Codesprachen

Mit Appium können Sie Tests in verschiedenen Codesprachen schreiben. Dies ist ein Vorteil des Client-Server-Modells. Das Appium-Entwicklungsteam kann alle Appium-Funktionen in nur einer Server-Codebasis implementieren, welche in JavaScript geschrieben ist (Appium Server = NodeJS Plattform). Dennoch können die Nutzerinnen und Nutzer, die Code in einer anderen Programmiersprache schreiben, Zugriff auf diese Funktionen erhalten. Der Zugriff erfolgt über die Appium Client Libraries, die uns Appium zur Verfügung stellt. Wenn wir zum Bespiel unsere automatischen Tests in Java schreiben möchten, müssen wir die entsprechenden Appium Java Libraries in unseren Appium Client integrieren.

Appium Client-Server-Modell

Wie bereits beschrieben senden wir unseren Testcode (Befehle/Requests) über den Appium Client mit den entsprechenden Libraries an den Appium Server. Als Appium Client kann zum Bespiel das Entwickler-Tool Eclipse dienen. Der Appium Server wiederum schickt unseren Testcode (Befehle/Requests) an das mobile Endgerät, auf dem dieser dann ausgeführt wird. Doch gehen wir etwas mehr ins Detail.

Damit der Appium Server den Appium Client Testcode (Befehle/Requests) interpretieren kann, nutzt er das WebDriver Protocol oder das ältere JSON Wire Protocol, welche unseren Testcode in einen HTTP RESTful request konvertieren.

Danach schickt der Appium Server unseren Testcode, je nachdem welches Endgerät wir ansprechen wollen, an das plattformspezifische Testframework, welches wiederum den Testcode auf dem Endgerät ausführt. Der Appium Server ist an dieser Stelle in der Lage, mit den unterschiedlichen Testframeworks zu kommunizieren.

Damit der Appium Server entscheiden kann, mit welchem dieser plattformspezifischen Testframeworks bzw. mit welchem Endgerät er kommunizieren soll, muss unser Testcode sogenannte „Desired Capabilities“ als JSON Object an den Appium Server mitschicken. In den Desired Capabilities geben wir zum Beispiel den Gerätenamen, die Plattform (iOS, Android…) und die Plattformversion an.

Appium Client-Server-Modell
Abbildung 7: Appium Client-Server-Modell

Es gibt nicht unbedingt nur ein Testframework pro Plattform. So gibt es beispielsweise unter Android drei verschiedene Automatisierungstechnologien von Google. Die älteste, UiAutomator, wurde von UiAutomator2 abgelöst. UiAutomator2 hat eine Vielzahl neuer Automatisierungsfunktionen hinzugefügt.

Das neueste Testframework heißt Espresso und funktioniert mit einem ganz anderen Modell als UiAutomator2, bietet jedoch eine viel größere Stabilität und Testgeschwindigkeit.

Sie können Ihre Appium-Tests anweisen, sich auf eine dieser Testframeworks zu beziehen, basierend auf deren spezifischen Funktionen und der Plattformunterstützung.

Theoretisch könnten Sie die Testframeworks auch direkt einsetzen. Appium bietet jedoch einen praktischen Rahmen für die verschiedenen Testframeworks, stellt sie mit demselben WebDriver-Protocol zur Verfügung und versucht, Verhaltensunterschiede zwischen den verschiedenen Testframeworks auszugleichen.

Appium als Rahmen für Testframeworks
Abbildung 8: Appium als Rahmen für Testframeworks

Wenn neue Testframeworks erscheinen, kann das Appium-Team ein Kommunikationsprotokoll (Driver) für diese erstellen, sodass Sie auf diese zugreifen können, ohne all Ihre Testskripte neu schreiben zu müssen. Dies ist die Stärke der Verwendung eines Standardprotokolls und der Client-Server-Architektur.

Es ermöglicht auch die plattformübergreifende Automatisierung. Anstatt zwei verschiedene Testframeworks in zwei verschiedenen Sprachen zu lernen, können Sie in vielen Fällen ein Appium-Skript schreiben und dieses auf unterschiedlichen Plattformen ausführen.

Wer Appium nutzt, für den ist es nicht erforderlich, viel über diese zugrunde liegenden Testframeworks zu wissen, da sie sich nur mit der Appium API befassen und beispielsweise keinen XCUITest- oder Espresso-Test schreiben.

Zusammenfassung

Zusammenfassend ist zu sagen: Appium ist ein Tool zur Automatisierung mobiler Anwendungen, welches von Selenium inspiriert wurde. Tatsächlich basieren Appium-Tests auf demselben Protocol wie Selenium-Tests. Selenium bietet seinen Nutzerinnen und Nutzern die Möglichkeit, Webbrowser zu steuern. Aus historischen Gründen wird es daher manchmal als „WebDriver“ oder „Selenium/WebDriver“ bezeichnet.

Wie Sie eventuell bereits am Namen erkennen können, wurde Appium so konzipiert, dass es so gut wie möglich mit Selenium kompatibel ist. Appium übernahm das gleiche Protocol wie Selenium, so dass Appium- und Seleniumtests größtenteils gleich aussehen und sich gleich „anfühlen“.

Tatsächlich wurden die Appium Client Libraries auf den Selenium Client Libraries aufgebaut. Es gab jedoch ein Problem: Das Selenium Protocol wurde nur zur Automatisierung von Webbrowsern entwickelt. Daher musste Appium dem Protocol Befehle hinzufügen, um mobilspezifische Automatisierung zu unterstützen. Dies bedeutet, dass Appium-Befehle eine Erweiterung der Selenium-Befehle sind.

Die zuvor aufgestellte Behauptung, dass die Einführung von Appium in unser Beispielprojekt aufgrund des Kosten-Nutzen-Faktors nicht sinnvoll wäre, ist also falsch. Es ist sogar davon auszugehen, dass eine Einführung, neben einer besseren Abdeckung hinsichtlich der Testautomatisierung, auch zu einer Prozessverbesserung beitragen kann.

Ich hoffe, dieser kurze Exkurs in die Welt der Testautomatisierung und in den technischen Hintergrund von Appium hat Ihnen etwas Freude bereitet.

In meinem zweiten Blog zum Thema Appium zeige ich Ihnen, wie wir Appium einrichten. Zusätzlich werde ich anhand konkreter Codebeispiele zeigen, was wir mit Appium in unserem Multiplattformprojekt leisten können. Dabei gehen wir auf die bereits angesprochenen Fälle ein.

Ich würde mich freuen, wenn Sie auch in den nächsten Beitrag dieser Blogreihe wieder reinschauen. Bis dahin, happy testing.

Pimp my testAUTOmation (Teil 3)

Ergebnisprotokolle und Reports

Mit Selenium lassen sich wie bei den meisten Testautomatisierungswerkzeugen Ergebnisprotokolle erzeugen. Diese maschinenlesbaren Dokumente in Formaten wie XML oder JSON sind nicht sehr benutzerfreundlich, aber sie können leicht in andere Werkzeuge eingebunden und damit lesbarer gemacht werden. Mit dieser Blogreihe möchte ich zeigen, wie sich mit einfachen Mitteln wichtige Funktionen in Selenium erweitern oder ausbauen lassen. Im ersten Teil habe ich vorgestellt, was Selenium 4 bringt und wie Screenshots eingesetzt werden können. Im zweiten Teil erstellten wir ein Video der Testdurchführung und im dritten Teil geht es um Reports. Dabei versuche ich die Ansätze nach ihrem Mehrwert (The Good) und ihren Herausforderungen (The Bad) zu bewerten und ggf. nützliche Hinweise (… and the Useful) zu geben.

Warum benötigen wir Reports?

Um die Frage nach dem “Warum“ zu beantworten, fange ich mit dem „schlimmsten“ Fall an: Die Auswertung und revisionssichere Ablage aller Testergebnisse ist in manchen Projekten verpflichtend vorgeschrieben, da hier gesetzliche oder andere Vorgaben eingehalten werden müssen. Bei Auftragsentwicklung kann das eine Forderung des Kunden sein. Bei Soft- und Hardwareentwicklung im Medizinbereich ist es eine Pflichtvorgabe für die Genehmigung und Zulassung durch die Behörden. Aber auch ohne diese Vorgaben bieten Reports und übersichtliche Protokolle einen Mehrwert für das Projekt. So lassen sich aus ihnen Kennzahlen und Trends ableiten, die das Team für seine Retrospektiven oder Weiterentwicklung benötigt.

Einfach mal ein Protokoll…

Es gibt viele Wege, einfache maschinenlesbare Testprotokolle zu erzeugen. Bei der Nutzung von automatisierten Tests (Selenium, JUnit) in Java-Projekten lässt sich über Maven das Plugin maven-surefire einbinden, welches während des Buildvorganges eine XML-Datei erzeugt, die die Ergebnisse eines Testlaufes aufzeichnet. Die XML-Datei beinhaltet den Namen der Testklasse und aller Testmethoden, die Gesamtdauer der Testdurchführung, die Dauer jedes Testfalles / jeder Testmethode sowie die Testergebnisse (tests, errors, skipped, failures).

… und was macht man damit.

Die maschinenlesbaren Protokolle werden meist automatisch im Buildwerkzeug erzeugt und in den Ergebnisbericht des Buildwerkzeuges eingebunden. So bindet Jenkins alle Ergebnisse der automatisierten Tests für Projekte ein, die mit Maven organisiert wurden. Darüber hinaus stehen in den meisten Buildwerkzeugen Plugins bereit, die die Testprotokolle einbinden oder sogar grafisch aufbereiten.

Die Projekte, die all ihre Testergebnisse dokumentieren müssen, stehen meist vor dem Problem, dass die Testergebnisse der verschiedenen Testarten (manuell, automatisiert etc.) in unterschiedlichen Werkzeugen erzeugt werden und damit in unterschiedlichen Formaten vorliegen. Darum bieten verschiedene Testmanagementwerkzeuge die Möglichkeit, die maschinenlesbaren Reports einzulesen. Damit stehen die Testergebnisse der automatisierten neben den manuellen Tests und können in einem Testbericht / Testreport zusammengefasst werden.

So lassen sich z. B. in dem Jira-Testmanagementplugin Xray die Testergebnisse für JUnit und NUnit manuell oder über eine Rest-API automatisch einlesen: https://confluence.xpand-it.com/display/public/XRAY/Import+Execution+Results.

Geht da noch mehr?

Sofern kein passendes Testmanagementwerkzeug vorhanden ist oder man eine Stand-alone-Variante benötigt, möchte ich noch das Werkzeug Allure Test Report vorstellen. Das Allure-Framework ist ein flexibles, leichtes und mehrsprachiges Testberichtstool mit der Möglichkeit, Screenshots, Protokolle usw. hinzuzufügen. Es bietet eine modulare Architektur und übersichtliche Webberichte mit der Möglichkeit, Anhänge, Schritte, Parameter und vieles mehr zu speichern. Dabei werden verschiedene Testframeworks unterstützt: JUnit4, JUnit5, Cucumber, JBehave, TestNG, …

Screenshot Allure Report

Um eine bessere Auswertung und Übersichtlichkeit in den Reports zu erzeugen, setzt das Allure-Framework eigene Annotations ein. Damit lassen sich die Ergebnisse der Testklassen und Testmethoden mit Features, Epics oder Stories verknüpfen. Über die Annotationen wie @Story, @Feature oder @Epic lassen sich zum Beispiel Testklassen oder Testmethoden mit den Anforderungen (Story, Epic, Feature) verknüpfen. Diese Verknüpfungen lassen sich dann in der Reportansicht auswerten und damit Aussagen zur Testabdeckung bzw. zum Projektfortschritt treffen.

Darüber hinaus lässt sich die Lesbarkeit der Testfälle durch die Annotation @Step und @Attachment verbessern. Wir können unseren Tesftfall (@Test) in einzelne Testmethoden aufteilen, um die Lesbarkeit und Wiederverwendbarkeit zu erhöhen. Mit der Annotation @Step des Allure-Frameworks lassen sich diese Testmethoden bzw. Testschritte im Testprotokoll anzeigen. Dabei unterstützt @Step die Anzeige einer Testschrittbeschreibung der verwendeten Parameter, die Schrittergebnisse sowie Attachments. Denn Testschritten lassen sich Texte in Form von String und Bilder in Form von byte[] anfügen. Siehe dazu das Codebeispiel …

Annotationen von Allure

@Feature("BMI Rechner - JUNIT")
public class TestAllureReport {
  
    @Test
    @Description("Aufruf des BMI-Rechners mit Testdaten für Untergwicht / Männer!")
    @Severity(SeverityLevel.CRITICAL)
    @Story("BMI Berechnung - Untergewicht für Männer")
    public void testUnderWeightMale() {
        inputTestdata("20", "200", "20", "Männlich");
        clickButtonCalc();
        compareResult("Untergewicht");
    }    
 
    @Step("EINGABE: Gewicht='{0}', Größe='{1}',Alter='{2}' und Geschlecht='{3}'")
    private void inputTestdata(String weight, String size, String age, String sex) {
        ...
    }
     
    @Step("Klick auf Berechnen")
    private void clickButtonCalc() {
        ...
    }
 
    @Step("Vergleiche, dass das Ergebnis auf '{0}' lautet")
    private void compareResult(String result) {
        ...
         
        // attach text
        attachment(str2);
         
        //make a screenshot and attach
        screenShot(driver, ".\\screenshots\\" ,"test_Oversized");
         
        ...
    }
    
 
    @Attachment(value = "String attachment", type = "text/plain")
    public String attachment(String text) {
        return "<p>" + text + "</p>";
    }
 
    @Attachment(value = "4", type = "image/png")
    private static byte[] screenShot(FirefoxDriver driver, String folder, String filename) {
 
        ...
         
        return new byte[0];
 
    }
     
}

… und das Ergebnis im Testprotokoll:

Screenshot Testprotokoll

Fazit

Mit Testprotokollen und Reports lassen sich sehr einfach automatisierte Testläufe erzeugen und in die eigene Toolkette einbinden. Dies ist zwar meist mit etwas Mehraufwand verbunden, aber dadurch werden Trends und Probleme schneller und besser erkannt.

Ergebnisprotokolle und Reports

The GoodThe Bad… and the Useful
• Visualisierung des aktuellen Status
• Es lassen sich Trends und Probleme erkennen

• Mehr Aufwand
• Neue Werkzeuge und Schnittstellen
• höhere Komplexität

• Allure Test Report → allure.qatools.ru/
• Xpand Xray → getxray.app/
• Plugins in Buildwerkzeugen

Pimp my testAUTOmation (Teil 2)

Videos der Testdurchführung aufnehmen

Mit dieser Blogreihe möchte ich zeigen, wie sich mit einfachen Mitteln wichtige Funktionen in Selenium einbauen lassen. Im ersten Teil habe ich vorgestellt, was Selenium 4 bringt und wie Screenshots eingesetzt werden können. Im zweiten Teil erstellen wir ein Video der Testdurchführung. Dabei versuche ich, die Ansätze nach ihrem Mehrwert (The Good) und ihren Herausforderungen (The Bad) zu bewerten und ggf. nützliche Hinweise (… and the Useful) zu geben.

Warum?

Aber zum Anfang stellen wir uns kurz die Frage: Warum ein Video bzw. einen Screencast der Testdurchführung aufzeichnen?

Mit einem Video haben wir eine Aufnahme des gesamten Testlaufs. Anders als mit einem Screenshot können wir so nicht nur das Testergebnis festhalten, sondern es lässt sich auch der Weg dorthin nachvollziehen.

Wie Screenshots können auch die Videos zum Debugging dienen und auf Probleme während des Testlaufes hinweisen. Darum ist es wie beim Screenshot sinnvoll, nur dann Videos zu erzeugen, wenn Probleme auftreten. Nach diesem Ansatz sollte die Video-Funktionalität um einen flexiblen und globalen Schalter erweitert werden, der sich je nach Notwendigkeit setzen lässt.

Aber die Videos können auch der Dokumentation der Testergebnisse dienen. In manchen Projekten ist eine ausführliche Dokumentation sogar verpflichtend vorgeschrieben, da hier gesetzliche oder andere Vorgaben eingehalten werden müssen.

Videos aufnehmen leicht gemacht

Da ich Selenium mit der Java-Ausprägung nutze, war mein erster Ansatz, Videos mit den „hauseigenen“ Funktionen von Java aufzunehmen bzw. ein passendes Framework zu nutzen. Meine erste Wahl fiel auf das Framework MonteCC, da sich hier mit der Hilfe von nur zwei Methoden der Bildschirm während der Testdurchführung aufnehmen ließ. In einer Methode vor dem Test wird die Videoaufnahme gestartet und in einer Methode nach dem Test wird die Aufnahme gestoppt und das Video im passenden Verzeichnis abgelegt.

private ScreenRecorder screenRecorder;
 
@BeforeEach
public void beforeTest() {
 
    GraphicsConfiguration gc = GraphicsEnvironment
            .getLocalGraphicsEnvironment()
            .getDefaultScreenDevice()
            .getDefaultConfiguration();
 
    try {
        this.screenRecorder = new ScreenRecorder(gc,
                new Format(MediaTypeKey, MediaType.FILE, MimeTypeKey, MIME_AVI),
                new Format(MediaTypeKey, MediaType.VIDEO, EncodingKey, ENCODING_AVI_TECHSMITH_SCREEN_CAPTURE,
                        CompressorNameKey, ENCODING_AVI_TECHSMITH_SCREEN_CAPTURE,
                        DepthKey, 24, FrameRateKey, Rational.valueOf(15),
                        QualityKey, 1.0f,
                        KeyFrameIntervalKey, 15 * 60),
                new Format(MediaTypeKey, MediaType.VIDEO, EncodingKey,"black",
                        FrameRateKey, Rational.valueOf(30)),
                null);
        this.screenRecorder.start();
 
    } catch (Exception e) {
        System.out.println("screenRecorder.start " + e.getMessage());
    }
}
 
@AfterEach
public void afterTest()  {
 
    try {
        this.screenRecorder.stop();
        List createdMovieFiles = screenRecorder.getCreatedMovieFiles();
        for (Object movie: createdMovieFiles) {
            File m = (File)movie;
            System.out.println("New movie created: " + m.getAbsolutePath());
        }
 
    } catch (IOException ioe) {
        System.out.println("screenRecorder.stop " + ioe.getMessage());
    }
}

Damit dies vor jedem Test passiert, nutzen wir die Annotations von JUnit:

@Test

Die Methode mit der Annotation @Test ist ein Testfall und wird bei der Testausführung gestartet und das Ergebnis im Testprotokoll erfasst.

@BeforeEach

Diese Methode wird vor jeder Testaufführung aufgerufen (siehe @Test).

@AfterEach

Diese Methode wird nach jeder Testaufführung aufgerufen (siehe @Test).

Wer eine komplette Aufzeichnung aller Testfälle benötigt, kann auch die Annotations @Before und @After nutzen, die vor allen bzw. nach allen Tests einer Testsuite (Testklasse) aufgerufen werden.

Große Nachteile von MonteCC sind, dass zum einen das letzte Release bereits mehr als sechs Jahre zurückliegt und zum anderen, dass die Videos im Format QuickTime vorliegen.

Als Alternative bot sich JavaCV (https://github.com/bytedeco/javacv) an. Die Bibliothek wird in GitHub fleißig gepflegt und speichert Videos im Format MPEG. Auch hier gibt es bei der Videoerzeugung zwei Methoden, die sowohl vor als auch nach dem Test aufgerufen werden können. Aber die JavaCV benötigt weitere Methoden, da parallel zum Testlauf in kurzen Abständen Screenshots erstellt und diese dann nach dem Test zu einem Video zusammenstellt werden. Eine ausführliche Anleitung findet ihr unter folgenden Link: https://cooltrickshome.blogspot.com/2016/12/create-your-own-free-screen-recorder.html.

Für den Einsatz beim automatisierten Testen habe ich folgende Änderungen vorgenommen:

/**
 *
 * https://github.com/bytedeco/javacv
 * https://cooltrickshome.blogspot.com/2016/12/create-your-own-free-screen-recorder.html
 */
public class RecordSeleniumJavaCV {
 
    // The WebDriver is a tool for writing automated tests of websites.
    FirefoxDriver driver;
 
    public static boolean videoComplete=false;
    public static String inputImageDir= "videos" + File.separator + "inputImgFolder"+File.separator;
    public static String inputImgExt="png";
    public static String outputVideoDir= "videos" + File.separator;
    public static String outputVideo;
    public static int counter=0;
    public static int imgProcessed=0;
    public static FFmpegFrameRecorder recorder=null;
    public static int videoWidth=1920;
    public static int videoHeight=1080;
    public static int videoFrameRate=3;
    public static int videoQuality=0; // 0 is the max quality
    public static int videoBitRate=9000;
    public static String videoFormat="mp4";
    public static int videoCodec=avcodec.AV_CODEC_ID_MPEG4;
    public static Thread t1=null;
    public static Thread t2=null;
    public static boolean isRegionSelected=false;
    public static int c1=0;
    public static int c2=0;
    public static int c3=0;
    public static int c4=0;
 
    /**
     * Explanation:
     * 1) videoComplete variables tells if user has stopped the recording or not.
     * 2) inputImageDir defines the input directory where screenshots will be stored which would be utilized by the video thread
     * 3) inputImgExt denotes the extension of the image taken for screenshot.
     * 4) outputVideo is the name of the recorded video file
     * 5) counter is used for numbering the screenshots when stored in input directory.
     * 6) recorder is used for starting and stopping the video recording
     * 7) videoWidth, videoFrameRate etc define output video param
     * 8) If user wants to record only a selected region then c1,c2,c3,c4 denotes the coordinate
     *
     * @return
     * @throws Exception
     */
    public static FFmpegFrameRecorder getRecorder() throws Exception
    {
        if(recorder!=null)
        {
            return recorder;
        }
        recorder = new FFmpegFrameRecorder(outputVideo,videoWidth,videoHeight);
        try
        {
            recorder.setFrameRate(videoFrameRate);
            recorder.setVideoCodec(videoCodec);
            recorder.setVideoBitrate(videoBitRate);
            recorder.setFormat(videoFormat);
            recorder.setVideoQuality(videoQuality); // maximum quality
            recorder.start();
        }
        catch(Exception e)
        {
            System.out.println("Exception while starting the recorder object "+e.getMessage());
            throw new Exception("Unable to start recorder");
        }
        return recorder;
    }
 
    /**
     * Explanation:
     * 1) This method is used to get the Recorder object.
     * 2) We create an object of FFmpegFrameRecorder named "Recorder" and then set all its video parameters.
     * 3) Lastly we start the recorder and then return the object.
     *
     * @return
     * @throws Exception
     */
    public static Robot getRobot() throws Exception
    {
        Robot r=null;
        try {
            r = new Robot();
            return r;
        } catch (AWTException e) {
            System.out.println("Issue while initiating Robot object "+e.getMessage());
            throw new Exception("Issue while initiating Robot object");
        }
    }
 
    /**
     * Explanation:
     * 1) Two threads are started in this module when user starts the recording
     * 2) First thread calls the takeScreenshot module which keeps on taking screenshot of user screen and saves them on local disk.
     * 3) Second thread calls the prepareVideo which monitors the screenshot created in step 2 and add them continuously on the video.
     *
     * @param r
     */
    public static void takeScreenshot(Robot r)
    {
        Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
        Rectangle rec=new Rectangle(size);
        if(isRegionSelected)
        {
            rec=new Rectangle(c1, c2, c3-c1, c4-c2);
        }
        while(!videoComplete)
        {
            counter++;
            BufferedImage img = r.createScreenCapture(rec);
            try {
                ImageIO.write(img, inputImgExt, new File(inputImageDir+counter+"."+inputImgExt));
            } catch (IOException e) {
                System.out.println("Got an issue while writing the screenshot to disk "+e.getMessage());
                counter--;
            }
        }
    }
 
    /**
     * Explanation:
     * 1) If user has selected a region for recording then we set the rectangle with the coordinate value of c1,c2,c3,c4. Otherwise we set the rectangle to be full screen
     * 2) Now we run a loop until videoComplete is false (remains false until user press stop recording.
     * 3) Now we capture the region and write the same to the input image directory.
     * 4) So when user starts the recording this method keeps on taking screenshot and saves them into disk.
     *
     */
    public static void prepareVideo()
    {
        File scanFolder=new File(inputImageDir);
        while(!videoComplete)
        {
            File[] inputFiles=scanFolder.listFiles();
            try {
                getRobot().delay(500);
            } catch (Exception e) {
            }
            //for(int i=0;i<scanFolder.list().length;i++)
            for(int i=0;i<inputFiles.length;i++)
            {
                //imgProcessed++;
                addImageToVideo(inputFiles[i].getAbsolutePath());
                //String imgToAdd=scanFolder.getAbsolutePath()+File.separator+imgProcessed+"."+inputImgExt;
                //addImageToVideo(imgToAdd);
                //new File(imgToAdd).delete();
                inputFiles[i].delete();
            }
        }
        File[] inputFiles=scanFolder.listFiles();
        for(int i=0;i<inputFiles.length;i++)
        {
            addImageToVideo(inputFiles[i].getAbsolutePath());
            inputFiles[i].delete();
        }
    }
 
    /**
     * Explanation:
     * 1) cvLoadImage is used to load the image passed as argument
     * 2) We call the convert method to convert the image to frame which could be used by the recorder
     * 3) We pass the frame obtained in step 2 and add the same in the recorder by calling the record method.
     *
     * @return
     */
    public static OpenCVFrameConverter.ToIplImage getFrameConverter()
    {
        OpenCVFrameConverter.ToIplImage grabberConverter = new OpenCVFrameConverter.ToIplImage();
        return grabberConverter;
    }
 
    /**
     * Explanation:
     * 1) We start a loop which will run until video complete is set true (done only when user press stop recording)
     * 2) We keep on monitoring the input  Image directory
     * 3) We traverse each file found in the input image directory and add those images to video using the addImageToVideo method. After the image has been added we delete the image
     * 4) Using the loop in step1 we keep on repeating step 2 and 3 so that each image gets added to video. We added a delay of 500ms so that this module does not picks a half created image from the takeScreenshot module
     * 5) When user press stop recording the loop gets broken. Now we finally traverse the input image directory and add the remaining images to video.
     *
     * @param imgPath
     */
    public static void addImageToVideo(String imgPath)
    {
        try {
            getRecorder().record(getFrameConverter().convert(cvLoadImage(imgPath)));
        } catch (Exception e) {
            System.out.println("Exception while adding image to video "+e.getMessage());
        }
    }
 
    /**
     * Explanation:
     * 1) We make a JFrame with the button for staring and stopping the recording. One more button is added for allowing user to record only a selected portion of screen
     * 2) If user clicks to select only certain region then we call a class CropRegion method getImage which helps in retrieving the coordinate of the region selected by user and update the same in variable c1,c2,c3,c4
     * 3) If user clicks on start recording then startRecording method is called
     * 4) If user clicks on stoprecording then stopRecording method is called
     */
    @BeforeEach
    public void beforeTest() {
 
        System.out.println("this.screenRecorder.start()");
 
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
        String timestamp  = dateFormat.format(new Date());
 
        outputVideo= outputVideoDir + "recording_" + timestamp + ".mp4";
 
        try {
            t1=new Thread()
            {
                public void run() {
                    try {
                        takeScreenshot(getRobot());
                    } catch (Exception e) {
                        System.out.println("Cannot make robot object, Exiting program "+e.getMessage());
                        System.exit(0);
                    }
                }
            };
            t2=new Thread()
            {
                public void run() {
                    prepareVideo();
                }
            };
            t1.start();
            t2.start();
            System.out.println("Started recording at "+new Date());
 
 
        } catch (Exception e) {
            System.out.println("screenRecorder.start " + e.getMessage());
        }
    }
 
    @AfterEach
    public void afterTest()  {
 
        System.out.println("this.screenRecorder.stop()");
 
        try {
            videoComplete=true;
            System.out.println("Stopping recording at "+new Date());
            t1.join();
            System.out.println("Screenshot thread complete");
            t2.join();
            System.out.println("Video maker thread complete");
            getRecorder().stop();
            System.out.println("Recording has been saved successfully at "+new File(outputVideo).getAbsolutePath());
 
        } catch (Exception e) {
            System.out.println("screenRecorder.stop " + e.getMessage());
        }
    }
 
    @Test
    public void testMe() {
         
        //toDo
 
    }
 
}

Gibt es einen Haken?

Somit haben wir nun mehrere Möglichkeiten, den automatischen Testlauf in einem Video festzuhalten, um bei Problemen diese nachvollziehen oder die Dokumentationspflichten erfüllen zu können.

Aber die Aufnahme während des Testdurchlaufes ist mit einem Risiko verbunden, dass der Tester / Testautomatisierer beachten sollte: Es ist ein Eingriff den normalen Testablauf, da wir ggf. die Timings der Geschwindigkeit ändern. Unser modifizierter Testlauf mit Videoaufnahme kann sich anders verhalten als ein Testlauf ohne Videoaufnahme.

Videos der Testdurchführung

The GoodThe Bad… and the Useful
• Aufnahme des gesamten Testlaufs
• Neben dem Testergebnis lässt sich auch der Weg dorthin nachvollziehen

• Es wird der Testlauf beeinflusst
• Verschiedene alte und kostenpflichtige Frameworks zur Videoaufnahme
• Codecs Probleme (nur QuicktimeView)
• JavaCV →
github.com/bytedeco/javacv




Einfache Anamnese der QA-Strategie für agile Teams

Mit Hilfe unseres agilen Visualisierungswerkzeugs, dem QA Navigation Board, möchten wir eine Methode vorstellen, mit der agile Entwicklungsteams typische QA-Problemfälle und deren Auswirkungen erkennen und diese beseitigen können.

Vergleichbar mit einem falschen Architekturansatz oder der Verwendung der falschen Programmiersprache kann eine falsche Test- und Qualitätssicherungsstrategie im Laufe des Projektes zu Beeinträchtigungen führen. Im besten Fall kommt es nur zu Verzögerungen oder Mehraufwand. Im schlechtesten Fall wird unzureichend getestet und es tauchen immer wieder schwerwiegende Abweichungen im Betrieb der Anwendung auf.

Einführung​

Die Probleme werden durch die agilen Entwicklungsteams bemerkt und die Auswirkungen in der Retrospektive dokumentiert, aber oft können sie wegen fehlender QA-Expertise nicht die Ursache erkennen und somit das Problem auch nicht beheben. Das Team benötigt in diesen Fällen Unterstützung durch einen agilen QA-Coach. Dieser zeichnet sich dabei zum einen durch seine Kenntnisse in der agilen Arbeitsweise aus, aber zum anderen auch durch seine Erfahrungen in der agilen Qualitätssicherung.

Der erste Schritt in der Arbeit des agilen QA-Coaches ist es, den aktuellen Stand des Testvorgehens des agilen Entwicklungsteams festzuhalten. Dazu nutzt er zum Beispiel in einem Workshop das sogenannte QA Navigation Board. Mit dem QA Navigation Board haben die Entwicklungsteams ein visuelles Hilfsmittel, mit dem sie die planerischen Aspekte der Qualitätssicherung beurteilen können. Dabei kann das QA Navigation Board innerhalb der Projektlaufzeit auch als Referenz des aktuellen Vorgehens und als Ansatz für potenzielle Verbesserung genutzt werden.

QA Navigation Board

Anti-Pattern​

Darüber hinaus ermöglicht das QA Navigation Board eine Anamnese des aktuellen Testvorgehens. Der agile QA-Coach kann durch die Visualisierung bestimmte Symptome für Anti-Pattern im Qualitätssicherungs- und Testprozess aufdecken und diese mit dem Team direkt besprechen. Als Anti-Pattern werden in der Softwareentwicklung Lösungsansätze bezeichnet, die ungünstig oder schädlich für den Erfolg eines Projektes oder einer Organisation sind.

Nachfolgend möchte ich verschiedene Anti-Pattern vorstellen. Neben den Eigenschaften zur Identifikation, stelle ich noch deren Auswirkungen dar. Im Sinne des Gegenstücks zum Anti-Pattern, dem Pattern, werden auch gute und bewährte Problemlösungsansätze vorgestellt.

Anti-Pattern – Wird schon gut gehen​

Dieses Anti-Pattern zeichnet sich durch das komplette Fehlen von Tests oder anderen Maßnahmen zur Qualitätssicherung aus. Dadurch ergeben sich schwerwiegende Konsequenzen für das Projekt und das Produkt. Das Team kann keine Qualitätsaussage über das Ergebnis seiner Arbeit treffen und besitzt damit streng genommen kein auslieferungsfähiges Produkt. Die Fehler tauchen beim Endanwender auf und sorgen damit immer wieder für Ablenkung im Entwicklungsprozess des Teams, da die sogenannten Incidents aufwendig analysiert und behoben werden müssen.

QA Navigation Board
Keine TestsAuswirkungenLösung
• Es gibt keine Tests• Keine Qualitätssausage• „Schnell weggehen“
• Getestet wird beim Anwender• QA einführen

Der Lösungsansatz ist einfach: Testen! Je eher Abweichungen gefunden werden, desto einfacher lassen sie sich beseitigen. Darüber hinaus sorgen Qualitätssicherungsmaßnahmen wie Codereviews und statische Codeanalyse als konstruktive Maßnahmen für eine Verbesserung.

Anti-Pattern – Dysfunktionaler Test​

Laut ISO 25010 gibt es acht verschiedene Qualitätskriterien für Software: Funktionalität, Effizienz, Kompatibilität, Benutzbarkeit, Zuverlässigkeit, Sicherheit, Wartbarkeit und Übertragbarkeit. Meist liegt der Schwerpunkt bei der Umsetzung neuer Software auf der Funktionalität, aber heutzutage spielen anderen Kriterien wie Sicherheit und Benutzbarkeit eine wichtige Rolle. Je höher die Priorität der anderen Qualitätskriterien ist, desto wahrscheinlicher ist es, für diese einen nicht-funktionalen Test vorzusehen.

Darum sollte die erste Frage zu Beginn eines Softwareprojektes lauten, auf welchen Qualitätskriterien der Fokus der Entwicklung und damit auch der Qualitätssicherung liegt. Um den Teams einen einfachen Einstieg in das Thema zu geben, nutzen wir den QA-Oktanten. Folgend der ISO 25010 beinhaltet der QA-Oktant die Qualitätskriterien für Softwaresysteme. Sie geben aber auch einen Hinweis auf die notwendigen Testarten, welche sich aus der gesetzten Gewichtung der unterschiedlichen funktionalen und nichtfunktionalen Kriterien ergeben.

Nur funktionale TestsAuswirkungenLösung
• Es gibt nur funktionale Tests• Keine Qualitätssausage über nicht-funktionale Kriterien• Wichtige Qualitätskriterien mit Kunden besprechen
• Es geht wie gewollt, aber …• Nicht-funktionale Testarten
• Mit dem QA-Oktanten starten

Anti-Pattern – Angriff der Dev-Krieger

Viele agile Entwicklungsteams – besonders Teams, die nur aus Entwicklern bestehen – setzen bei ihren QA-Maßnahmen nur auf entwicklungsnahe Tests. Meist kommen hier nur Unit- und Komponententests zum Einsatz. Diese lassen sich einfach im gleichen Entwicklungswerkzeug schreiben und schnell in den Entwicklungsprozess integrieren. Besonders komfortabel ist dabei die Möglichkeit, dass sich über Code Coverage Tools eine Aussage über die Abdeckung der Tests gegenüber dem Code geben lässt. Schnell tritt nämlich eine Sicherheit ein, wenn das Code Coverage Tool eine 100%-ige Testabdeckung meldet. Doch die Problematik steckt im Detail bzw. hier in der Komplexität. Für einfache Anwendungen wäre dieses Vorgehen ausreichend, aber bei komplexen Anwendungen treten Probleme auf.

Bei komplexen Anwendungen können trotz einer komfortablen Unit-Test-Abdeckung Fehler auftauchen, die sich erst durch aufwendige System- und End2End-Tests entdecken lassen. Und für diese aufwendigen Tests ist es notwendig, ein erweitertes QA-Know-how im Team zu haben. Tester oder geschulte Entwickler müssen auf höheren Teststufen der Komplexität der Anwendung entgegentreten, um hier eine passende Qualitätsaussage zu treffen.

QA Navigation Board
Angriff der DevOnlyAuswirkungLösung
• Nur entwicklungsnahe Tests• Kein End2End-Test• Tester ins Team holen
• Kein Tester im Team• Bugs treten bei komplexen Features auf• Auf höheren Teststufen testen
• 100% Codeabdeckung• Schnell

Anti-Pattern – Die Spanische Variante

Die Zeit, in der eine Funktion in den Code gebracht wurde und dann auf dem Zielsystem landet, wird immer kürzer. Damit verkürzt sich auch die Zeit für einen umfangreichen Test immer weiter. Für agile Projekte mit festen Iterationen durch Sprints ergibt sich ein weiteres Problem: Hier wird die Anzahl der zu prüfenden Funktionen mit jedem Sprint größer.

Reine klassische manuelle Tests kommen hier an ihre Grenzen. Darum sollten Tester und Entwickler gemeinsam an einer Testautomatisierungsstrategie arbeiten.

QA Navigation Board
Manual WorkAuswirkungLösung
• Es gibt nur manuelle Tests• Späte Rückmeldung bei Fehlern• QA auf alle Schultern verteilen
• Tester überfordert• Auf allen Teststufen testen
• Automatisierung einführen

Anti-Pattern – Automatisierte Regressionslücke

Das andere Extrem wäre ein Projekt ohne manuelle Tests. Dies bedeutet zwar eine hohe Integration in die CI-/CD-Prozesse und eine schnelle Rückmeldung bei auftretenden Fehlern, aber auch vermeidbare Probleme. Eine hohe Rate an Testautomatisierung ist mit einem großen Aufwand verbunden – sowohl bei der Erstellung der Tests als auch bei der Wartung. Und je höher die Komplexität der Anwendungsfälle ist und je schwieriger die verwendeten Technologien sind, desto höher ist die Wahrscheinlichkeit, dass durch Probleme während des Testdurchlaufes dieser stoppt oder aufwendige Prüfungen von Testabweichungen notwendig sind. Außerdem prüfen die meisten automatisierten Tests nur die Regression ab. Durch automatisierte Tests würden somit nie neue Fehler gefunden, sondern nur die Funktionsweise der Altfunktionen geprüft.

Darum sollte immer mit einem gesunden Augenmaß automatisiert werden und parallel durch manuelle und ggf. durch explorative Tests nach neuen Abweichungen Ausschau gehalten werden.

QA Navigation Board
100% TestautomationAuswirkungLösung
• Es gibt nur automatisierte Tests• Sehr viel Aufwand• Mit Augenmaß automatisieren
• Alle überfordert• Manuelles Testen hat seinen Sinn
• Build Stops durch Problemfälle

Anti-Pattern – Testsingularität

Tests aus unterschiedlichen Teststufen und -arten haben jeweils einen unterschiedlichen Testfokus. Damit ergeben sich auch unterschiedliche Anforderungen an die Testumgebung wie Stabilität, Testdaten, Ressourcen etc. Entwicklungsnahe Testumgebungen werden sehr oft mit neuen Versionen versorgt, um die Entwicklungsfortschritte zu prüfen. Für die höheren Teststufen oder andere Testarten benötigt man einen stabileren Versionsstand über eine längere Zeit.

Um nicht ggf. die Tests durch einen geänderten Softwarestand bzw. eine geänderte Version zu kompromittieren, sollte es für jede Testart eine Testumgebung geben.

QA Navigation Board
One Test EnvironmentAuswirkungLösung
• Es gibt nur eine Testumgebung• Kein Testfokus möglich• Mehrere Testumgebungen
• Kompromittierte Tests• Nach Teststufe oder Testfokus
• Keine produktionsnahen Tests• „Pro Testart eine Testumgebung“

Anti-Pattern – BauManuFaktur

Moderne Entwicklung lebt von einer schnellen Auslieferung und eine zeitgemäße Qualitätssicherung von der Integration der automatisierten Tests in den Build-Vorgang sowie der automatisierten Verteilung des aktuellen Softwarestandes auf die unterschiedlichen (Test-) Umgebungen. Ohne ein Build- oder CI-/CD-Werkzeug können diese Funktionen nicht bereitgestellt werden.

Sofern es in einem Projekt noch Aufgaben zur Bereitstellung eines CI-/CD-Prozesses gibt, können diese am Board als „To Dos“ markiert werden.

QA Navigation Board
No Build ToolAuswirkungLösung
• Es gibt kein Build-Werkzeug• Keine CI/CD• CI/CD einführen
• Langsame Auslieferung• Lücken am Board markieren
• Späte Testergebnisse
• Ressourcenabhängig

Anti-Pattern – Early Adopter

Neue Technologien bringen meist auch neue Werkzeuge mit sich und neue Versionen neue Funktionen. Aber die Einführung neuer Werkzeuge und das Update auf neue Versionen birgt auch ein Risiko. Auch hier ist es ratsam, mit Bedacht vorzugehen und nicht alle Teile/Werkzeuge des Projektes auf einmal zu ändern.

QA Navigation Board
Early AdopterAuswirkungLösung
• Einfach immer das neueste …• Herausforderungen in der Einarbeitung• Kein Big Bang
• Skill-Schwächen• Alte Tools kennt man
• Neue Probleme• Skill-Schwächen am Board markieren