JaCoCo ist eine Open-Source-Bibliothek für Java, die die Code-Abdeckung (Code Coverage) einer Applikation misst. Die Code-Abdeckung ist ein wichtiges Kriterium für die Beurteilung der Testabdeckung einer Applikation, denn durch geeignete Tests und eine hohe Testabdeckungsrate wird der Produktionscode gründlich überprüft.

Einige Features von JaCoCo sind beispielsweise die Erstellung von Reports in verschiedenen Formaten (HTML, XML, CSV) und die Integration in IDEs und CI – Pipelines. In Kombination mit SonarQube oder Jenkins kann somit die Code Coverage außerhalb der IDE stattfinden und durchs Reporting für das Entwicklungsteam zentral und transparent verfügbar gemacht werden.

In diesem Artikel zeige ich die Einrichtung von JaCoCo mit JUnit Tests, sowie die Integration der Ergebnisse in SonarQube.

Testapplikation

In den folgenden Beispielen werden wir ein simples Calculator-Programm verwenden, das eine ganzzahlige Division durchführt. Wichtig zu wissen: JaCoCo benötigt nicht den tatsächlichen Quellcode einer Applikation, um Reports über die Coverage Rate der Tests zu erstellen!

public final class Calculator {
    private Calculator() {}

    public static int divide(int a, int b) {
        int result = a / b;
        boolean resultWasPositive = false;
        if (result < 0)
            System.out.println("Negative result: " + result);
        else {
            System.out.println("Positive result: " + result);
        }
        return result;
    }
}

Das Ergebnis der Division wird in der Konsole ausgegeben und schließlich an den Aufrufer zurückgegeben. Die Fehler dieses Codes sind eindeutig erkennbar. Wie hilft uns nun JaCoCo, bessere Tests zu schreiben?

JaCoCo-Konfiguration

In der pom.xml-Datei des Maven-Projekts, fügen wir JaCoCo als dependency ein:

<dependencies>
        ....
        <dependency>
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
            <version>0.8.8</version>
        </dependency>
      ....
</dependencies>

Für einfache Unit-Tests, reichen 2 Goals für das Plugin (weitere Goals hier).

<build>
        <plugins>
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>0.8.8</version>
                <executions>
                    <execution>
                        <id>default-prepare-agent</id>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                        <configuration>
                            <destFile>
                                ${project.build.directory}/coverage-reports/jacoco.exec
                            </destFile>
                        </configuration>
                    </execution>

                    <execution>
                        <id>default-report</id>
                        <phase>test</phase>
                        <goals>
                            <goal>report</goal>
                        </goals>
                        <configuration>
                            <dataFile>${project.build.directory}/coverage-reports/jacoco.exec</dataFile>
                            <outputDirectory>${project.reporting.outputDirectory}/jacoco</outputDirectory>
                        </configuration>
                    </execution>

                </executions>
            </plugin>
        </plugins>
    </build>
  • prepare-agent: Bereitet die JaCoCo-Runtime vor, registriert die Anzahl der von Tests ausgeführten Zeilen usw. Zusätzlich kann hier über das <configuration>-Tag angegeben werden, wo und unter welchem Namen der erstellte Report (im Binärformat) gespeichert werden soll (standardmäßig jacoco.exec).
  • report: Erstellt die lesbaren Reports (XML, HTML oder CSV) für Code Coverage in der Testphase. Zusätzlich kann hier angegeben werden, wo die Reports gespeichert werden sollen und wo die jacoco.exec-Datei zu finden ist, falls diese in dem prepare-agent Goal konfiguriert wurde.

Testfälle schreiben

Nun wollen wir einen einfachen Testfall schreiben, der überprüfen soll, ob die ganzzahlige Division von 10 und 4 das Ergebnis 2 zurückliefert und messen anschließend seine Testabdeckung.

public class CalculatorTest {

    @Test
    public void testDivision() {
        int a = 10;
        int b = 4;
        int expected = 2;
        int actual = Calculator.divide(a, b);
        assertEquals(expected, actual);
    }
}

Die Report-Datei über die Code-Abdeckung unserer Tests finden wir  nach der Ausführung von mvn test standardmäßig unter /target/site/jacoco/index.html.

Was sehen wir hier? Unser Testfall mit den Eingaben 10 und 4 hat eine Code-Abdeckung von 64% erreicht. 11 Anweisungen wurden nicht erreicht und nur eine von 2 Verzweigungen (da nur ein if-else-Konstrukt im ursprünglichen Programmcode) wurde ausgeführt. Wir haben also das Programm unzureichend getestet und den Testfall mit negativen Zahlen vergessen. Das können wir genauer sehen, wenn wir auf das Element divide(int, int) im Report klicken.

Mit der folgenden Farbkodierung:

  • Grün: wurde völlig ausgewertet während des Testens
  • Gelb: nur partielle Auswertung
  • Rot: keine Ausführung durch die Tests

Wir müssen also einen weiteren Testfall schreiben, der auch die Verzweigung im if-Fall ausführt.

@Test
    public void testDivision_positive() {
        int a = 10;
        int b = 4;
        int expected = 2;
        int actual = Calculator.divide(a, b);
        assertEquals(expected, actual);
    }
    @Test
    public void testDivision_negative() {
        int a = 10;
        int b = -5;
        int expected = -2;
        int actual = Calculator.divide(a, b);
        assertEquals(expected, actual);
    }

Die erweietrten Tests erreichen nun eine vollständige Anweisungs- und Verzweigungsüberdeckung. Nichtsdestotrotz ist die Code Abdeckung keine Grundlage für die Qualität der Tests oder der Software! In der divide-Methode der Calculator-Klasse wird z.B. überhaupt nicht auf Division durch 0 geachtet!

Mit JaCoCo lässt sich auf diese Weise der Umfang der dynamischen Qualitätssicherung durch die aktive Testdurchführung messen und transparent beleuchten. Doch etliche Probleme mit der Code-Qualität lassen sich auch bereits vor der Testdurchführung durch die statische Code-Analyse identifizieren. Und genau hier kommt ein weiteres Werkzeug ins Spiel: SonarQube.

Integration mit SonarQube und Jenkins

Mit SonarQube lässt sich die statische Qualität des Codes messen und überprüfen. Die Funktionsweise von SonarQube ist folgendermaßen (übernommen von der offiziellen Dokumentation):

SonarQube Instance Components
  1. Entwickler schreiben Code und commiten diesen zu einem Repository.
  2. Eine CI-Pipeline durchläuft automatisch die verschiedenen Stages (Build, Tests…). Ein integrierter SonarQube Scanner analysiert die Ergebnisse.
  3. Die Analyse vom Scanner wird auf einem SonarQube Server hochgeladen und die Entwickler bekommen nun Feedback im Dashboard, als E-Mail oder direkte Benachrichtigung in IDE durch sonarlint.

SonarQube Scanner Plugin für Jenkins ermöglicht eine zentrale Konfiguration des SonarQube-Servers in Jenkins. Somit lässt sich in der CI-Pipeline eine Analyse mit einem SonarScanner (z.B. SonarScanner für Maven) starten, die nach ihrer Ausführung auf der Jenkins Job Seite zum SonarQube Dashboard verlinkt (wie im Schritt 3. der Funktionsweise erläutert). Sehen wir uns das Dashboard an.

Hier ist eine Zusammenfassung der SonarQube-Analyse zu finden mit diesen Bezeichnungen:

  • Quality Gate Status: Hier geht es letztendlich nur um die Frage „Ist mein Projekt bereit für ein Release?„. Um diese Frage zu beantworten, können wir Mindestanforderungen stellen wie z.B. eine Code Coverage Rate von mind. 80%. Die Quality Gates sind idealerweise für alle Projekte gleich, lassen sich aber einzeln einstellen, da wir ja per Projekt unterschiedliche Anforderungen haben können (z.B. verschiedene Coverage Rates für Java oder Web-Applikationen). Außerdem kann die Jenkins Pipeline unterbrochen werden, wenn der Quality Gate Status fehlgeschlagen ist.
  • Bugs, Vulnerabilities, Security Hotspots: keine für den verwendeten Code oder die 2 Unit Tests
  • Code Smells: im Zusammenhang mit der Wartbarkeit des Codes. Je mehr Code Smells, desto schwieriger ist es, den Code zu warten. Änderungen am Code können sogar zu zusätzlichen Fehlern in der Software führen
  • Debt: Die geschätzte Zeit, die benötigt wird, um alle Wartbarkeitsprobleme / Code Smells zu beheben

In der Calculator-Klasse aus dem o.s. Beispiel werden durch SonarQube 4 Code Smells identifieziert:

  • Wir haben für die Klasse kein package definiert,
  • deklarieren unnötigerweise die boolean-Variable resultWasPositive, ohne sie wieder zu verwenden,
  • und uns wird vorgeschlagen, statt System.out ein Logger zu benutzen.

Man kann für zusätzliche Informationen auf Why is this an issue? klicken, um mehr über das zugrundeliegende Problem zu erfahren.

Die restlichen 3 Code Smells sind in der Testklasse, die sich aber alle auf den Modifier public der CalculatorTest-Klasse und der Testmethoden beziehen.

In diesem Artikel haben wir einfache Möglichkeiten für die Einrichtung und Nutzung von JaCoCo und SonarQube beschrieben. Probiere es am besten gleich in Deinen Projekten aus – die investierte Zeit zahlt sich i.d.R. durch die schnellere Fehlerfindung und Analysemöglichkeiten sehr schnell wieder aus.

 

Allure Reporting ist eines der beliebtesten Open Source Produkte im Testbereich. Aus gutem Grund! Die Reports aggregieren die benötigten Daten sehr übersichtlich. Die Anbindung an die meisten Testframeworks wie Cucumber, TestNG, Selenide und andere funktioniert in der Regel reibungslos.

Spannend wird es bei Allure nur, wenn es um spezielle Anforderungen geht. Es können Postprocessing Aggregationen von unterschiedlichen Runs sein, aber auch das Anhängen von Dateien (Log Files oder Screenshots…) im Test-Lebenszyklus. Um den letzten Punkt geht es in diesem Artikel.

Weiterlesen

Tester führen Tests gerne in Docker Containern aus, soweit so bekannt.. Auch dass wir alle ganz gerne git verwenden, wundert eigentlich nicht wirklich. Nur kann die Kombination von beiden auch kleinere Probleme bereiten. So sind auch bei uns spontan, von einem Tag auf den anderen sämtliche Testfälle beim Cleanup der Umgebung ausgestiegen mit der Fehlermeldung:

+ git clean -fdx
fatal: unsafe repository ('/usr/share/jenkins/workspace/tests/nightly' is owned by someone else)
To add an exception for this directory, call:

	git config --global --add safe.directory '/usr/share/jenkins/workspace/tests/nightly'

Weiterlesen

Mit der Version 1.17 hat Playwright seine API aktualisiert und bietet seitdem neue Methoden zur Interaktion mit iframes. Hinzu kommen außerdem für Java neue Playwright- und LocatorAssertions-Klassen, die für Assertions in Testfällen verwendet werden können. Diese warten bis zum Eintreffen einer Bedingung, beispielsweise bis ein DOM-Node einen bestimmten Text hat. Sehen wir uns die einzelnen Updates an.

Weiterlesen

Playwright Framework unterstützt mehrere Verfahren zum Auffinden von Oberflächenelementen auf einer Webseite. Neben den allgemein bekannten Selektoren gibt es in Playwright noch weitere Konzepte wie  ElementHandle und Locator, die die Suche nach DOM-Elementen auf einer Webseite unterstützen und im diesem Artikel näher beleuchtet werden.

Weiterlesen

Einbindung von Playwright unter JUnit

Nachdem wir in einem anderen Artikel die grundlegende Einrichtung und Verwendung von Playwright demonstriert haben, wollen wir nun Playwright einsetzen, um mit JUnit die echten Tests einer Webanwendung zu schreiben. Weiterlesen

E2E-Tests haben u.a. den Nachteil, instabil und langsam zu sein. Aus diesem Grund hat Microsoft die Open-Source Playwright-API entwickelt, die als E2E Testframework der nächsten Generation gilt. Mit Playwright verfolgt man das Ziel, die browserübergreifende Webautomatisierung schneller und zuverlässiger zu gestalten. Dabei basiert Playwright auf einer ereignisgesteuerten (sog. event-driven) Architektur, welche automatisch auf Browser-Ereignisse wie Seitennavigation, Netzwerkanfragen oder DOM-Änderungen wartet. Mit neueren Versionen kommen immer weitere Features hinzu wie beispielsweise Geolokalisierung oder Mobile Emulation, um mobile Webseiten zu testen. Playwright API wird für verschiedene Programmiersprachen bereitgestellt: Java, Python, C#, JavaScript / TypeScript. In diesem Beitrag geht es um die Einrichtung von Playwright mit Java.

1. Einrichtung der Entwicklungsumgebung

Wir benötigen zuerst eine Entwicklungsumgebung für Java, die auf der folgenden Seite heruntergeladen werden kann: https://www.jetbrains.com/de-de/idea/download/. Einfach die Community-Version auswählen, die .exe-Datei ausführen und die Installationsschritte durchführen.

2. Maven installieren

Zur schnellen und einfachen Einrichtung von Playwright verwenden wir das Build-Management-Tool Maven, mit welchem die Playwright API Bibliotheken als Abhängigkeiten in Java Projekte automatisiert eingebunden werden. Zur Installation von Maven gehen wir wie folgt vor:

  1. https://maven.apache.org/download.cgi besuchen und das Binary zip-Archiv herunterladen
  2. Die Datei in einem beliebigen Ordner entpacken, z.B. in C:/ program files /
  3. Nach dem Entpacken, den bin-Ordner zum Systempfad hinzufügen

Systemumgebungsvariablen bearbeiten

In der Suchleiste env eintippen und Systemumgebungsvariablen bearbeiten auswählen

Umgebungsvariablen auswählen

Auf Umgebungsvariablen klicken

Path bearbeiten

Path auswählen und auf Bearbeiten klicken

bin-Ordner auswählen

Neuen Eintrag erstellen, zum bin-Ordner von dem entpackten Apache-Maven Archiv navigieren und diesen selektieren

  1. cmd.exe öffnen und mit mvn -v oder mvn –version überprüfen, ob Maven richtig installiert wurde

Bei Problemen die Hinweise zur Installation beachten: https://maven.apache.org/install.html

3. Neues Playwright Projekt erstellen

Mit Maven sollen möglichst viele Schritte automatisiert werden, wie etwa die Erstellung eines Projekts, das Testen usw. Die sog. Archetypes bieten eine Art „Gerüst“ für unterschiedliche Typen von Softwareprojekten an, deren Struktur dem Standard von Maven entspricht. Der Befehl mvn -B archetype:generate -DgroupId=de.simplytest -DartifactId=mein-maven-projekt -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 erstellt das einfachste Maven-Projekt in einem Verzeichnis mit dem Namen mein-maven-projekt . Mehr über die Maven-Archetypes erfährt man hier. Den Ordner öffnen wir in Intellij und fügen Playwright unter dem XML-Knoten dependencies in der pom.xml-Datei ein. Falls eine Warnung kommt, einfach auf Trust Project klicken.

<dependencies>
    <dependency>
      ...
    </dependency>
 
    <dependency>
      <groupId>com.microsoft.playwright</groupId>
      <artifactId>playwright</artifactId>
      <version>1.14.1</version>
    </dependency>
     
  </dependencies>

Außerdem sollten wir unter dem properties-Tag maven compiler source und maven compiler target zu 1.8 ändern, um die aktuellen Java 8 Features verwenden zu können.

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

4. Erste Schritte mit Playwright in Java – „Titel einer Seite ausgeben“

In mein-maven-projekt > src > main > java > de.simplytest > App.java befindet sich die main-Methode, die automatisch mit der Generierung der Archetype angelegt wird. Wir können natürlich aber ebenfalls weitere Java-Klassen erstellen und zum Projekt hinzufügen. Nehmen wir den folgenden Code als Programmbeispiel. Hier starten wir Firefox, navigieren dann zur offiziellen Playwright-Webseite und geben anschließend den Titel der Seite aus.

package de.simplytest;
 
import com.microsoft.playwright.*;
 
public class App 
{
    public static void main(String[] args )
    {
        try (Playwright playwright = Playwright.create()) {
            Browser browser = playwright.firefox().launch(new BrowserType.LaunchOptions().setHeadless(false));
            Page page = browser.newPage();
            page.navigate("http://playwright.dev");
            System.out.println(page.title());
        }
    }
}

Playwright öffnet den Browser standardmäßig ohne User Interface im sogenannten headless-Modus, also sehen wir nicht wirklich die interaktive Ausführung des Programms. Um das zu ändern, setzen wir mittels LaunchOptions den headless-Flag auf false und eventuell auch setSlowMo, um die Ausführungszeit der API zu verlangsamen.

Programm starten

Als Letztes geben wir den folgenden Befehl ein, um das Programm über Terminal auszuführen: mvn compile exec:java -Dexec.mainClass=de.simplytest.App

Am Ende sehen wir den Titel der Webseite : Fast and reliable end-to-end testing for modern web apps

Ihr wollten schon immer eine mobile Anwendung mit Appium automatisieren, wisst aber nicht wie ihr am besten loslegt?

In unserem Appium Tutorial zeigen wir euch die wichtigsten Schritte auf dem Weg zum ersten automatisierten Test mit Appium.

In diesem Beitrag geht es los mit dem Teil 1: Einrichtung von Appium und Android Studio unter Windows.

 

Weiterlesen

Testautomatisierung mit Cypress vs. Selenium Cypress und Selenium sind bekannte Testwerkzeuge, die für die Automatisierung von Webapplikationen eingesetzt werden. Selenium ist ein Open-Source-Automatisierungsframework, das in unterschiedlichen Produktversionen vorhanden ist.  Die Automatisierungslösung Selenium existiert schon seit 2004 und ist ein etabliertes Produkt mit einer großen Nutzerbasis weltweit. Das End-to-End-Tool Cypress hingegen ist seit 2014 ein Newcomer auf dem Markt, welches sich wie Selenium für die Automatisierung von Webapplikationen eignet. Cypress hat in den letzten Jahren durch seine […]

Open-Source SeleniumDragDrop Nuget

Vor einigen Jahren haben wir in einem unserer Blog Beiträge für die Lösungsmöglichkeit berichtet, wie man auf HTML 5 Seiten Drag & Drop Testautomatisierung mit HTML 5 implementeiren kann.

Der Hintrgrund war, dass die offizielle Selenium Drag & Drop API aus der Actions Klasse auf HTML 5 Seiten nicht richtig funktioniert und selbst die Referenz-Implementierungen von W3C Standard nicht autoamtisieren kann. Der zugehörige Bug-Request für Selenium Web Driver wurde bereits im Jahr 2012 angelegt. Leider ist er nach inzwischen 8 Jahren immer noch ungelöst 🙁

Da die Notwenigkeit der Drag & Drop Testautomtisierung mit Selenium aufgrund von immer komplexer Geschäftsapplikationen im Web immer häufiger angefragt wird, haben wir die Drag&Drop Implementeirung auf GitHub als Open Source Projekt bereitgestellt und ein fertiges Nuget Paket für C# veröffentlicht.

Im Rahmen dieser Implementierung wird die bereits beschriebene alternative Drag & Drop Umsetzung mit einem JavaScript umgesetzt, das automatisch augerufen wird.

Bei der Verwendung von Nuget Paket für Drag&Drop kann die Testautomatisierung von Drag&Drop in nur wenigen Schritten realisiert werden:

  1. Drag & Drop Nugen Paket SeleniumDragDrop in C# Solution einbinden
  2. Quell- und Ziel-Elemente für Drag & Drop auf der Web Seite finden
  3. DragDropHelper instanzieren
  4. Drag & Drop Operation für Quell- und Ziel-Elemente aufrufen

Die Automatisierung von Drag&Drop auf der W3C Refernz-Seite für HTML 5 Drag & Drop kann damit etwa wie folgt aussehen:

    IWebDriver driver = new ChromeDriver(Environment.CurrentDirectory);
    try
    {
        driver.Navigate().GoToUrl("https://www.w3schools.com/html/html5_draganddrop.asp");

        IWebElement sourceEl = driver.FindElement(By.Id("drag1"));
        IWebElement targetEl = driver.FindElement(By.Id("div2"));

        SeleniumDragDrop.DragDropHelper dragdrop = new SeleniumDragDrop.DragDropHelper(driver);
        dragdrop.DragAndDrop(sourceEl, targetEl);

        Assert.IsNotNull(targetEl.FindElement(By.Id("drag1")));
    }
    finally
    {
        driver.Quit();
    }

Viel Spaß beim Ausprobieren.