Skip to main content

Unit-Tests in Java schreiben

Artikel von

Lewis Gavin

feature java dto

18. November 2022

0 Min. Lesezeit

Tests sind eine wichtige Best Practice bei der Softwareentwicklung. Unit-Tests sind eine von zahlreichen Methoden, mit denen wir sicherstellen können, dass unser Code funktioniert und optimal arbeitet. Als Entwickler können wir Unit-Tests schreiben, um einzelne Komponenten (Units) des Anwendungscodes zu überprüfen, etwa eine bestimmte Methode. Die Idee ist, für jeden Codeabschnitt einen oder mehrere Unit-Tests zu schreiben und sie bei jeder Änderung auszuführen, damit Fehler so früh wie möglich erkannt werden. Für neuen Code sollten Tests hinzugefügt werden, während (oder sogar bevor) der Code geschrieben wird. Bei vorhandenem Code sollten Tests, falls es noch keine gibt, ergänzt werden, um einen Großteil – wenn nicht alle – Ausführungspfade der Anwendungslogik abzudecken.

Unit-Tests sollen alle externen Abhängigkeiten ausschließen und bestätigen, dass sich ein bestimmter Codeabschnitt in verschiedenen Situationen wie erwartet verhält. Dazu kann eine Methode wiederholt mit jeweils neuen Parametern aufgerufen und geprüft werden, ob sie den richtigen Wert zurückgibt, eine Ausnahme auslöst oder eine bestimmte Aufgabe erledigt.

Viele Java-Entwickler verwenden eines der verfügbaren Unit-Test-Frameworks: JUnit. In diesem Beitrag erfahren Sie, wie Sie JUnit 5 installieren und verwenden, um Unit-Tests für Java-Code zu schreiben. Zum Schreiben der Tests verwenden wir die integrierte Entwicklungsumgebung (IDE) VSCode und führen sie mit Java 11 und Maven aus. Tools wie Eclipse und IntelliJ funktionieren jedoch ähnlich, sodass Sie den Schritten folgen können.

Eine größere Auswahl an Tools für die Überprüfung Ihres Java-Codes finden Sie in unserem Beitrag zu Tools für Java-Code-Reviews oder in unserem Beitrag zur Java-Sicherheit, der Ihnen weitere Grundlagen vermittelt.

So schreiben Sie Ihren ersten Unit-Test in Java

In diesem Abschnitt installieren wir das JUnit-Framework und schreiben einige Unit-Tests. Später führen wir die Tests für dieses Beispiel-Codeprojekt aus. Das Projekt ist bereits mit dem Anwendungscode und einer Vorlage für eine Testklasse vorkonfiguriert, die alles enthält, was wir brauchen, um mit dem Hinzufügen von Tests zu beginnen.

Sehen wir uns zunächst den Beispielcode an, bevor wir mit dem Schreiben unserer Tests beginnen.

package com.snyk.unittestdemo;

public class App 
{
    public static void main( String[] args )
    {
        try {
            System.out.println(generateUpdateUserFirstNameStatement("John", "abcdef1234567"));
        }
        catch (Error e){
            e.printStackTrace();
        }
    }

    public static String generateUpdateUserFirstNameStatement(String firstName, String userId) throws Error{
        if(userId.contains(";") || firstName.contains(";")){
            throw new Error("parameters may contain SQL injection");
        }
        return "UPDATE TABLE user SET first_name = '" + firstName + "' WHERE user_id = '" + userId +"';" ;
    }

}

Unsere Anwendung verfügt über eine main-Methode, die die Methode generateUpdateUserFirstNameStatement aufruft und die Ausgabe ausgibt. Wenn beim Aufruf der Methode generateUpdateUserFirstNameStatement ein Fehler auftritt, fängt die Anwendung die Ausnahme ab und gibt den Stacktrace aus.

Die Methode generateUpdateUserFirstNameStatement ist eine einfache Methode, die zwei String-Parameter entgegennimmt und daraus eine SQL-UPDATE-Anweisung erstellt. Der Code löst einen Fehler aus, wenn einer der Parameter ein Semikolon enthält, da die Eingabe wahrscheinlich eine SQL-Injection enthält.

Diese Methode eignet sich hervorragend als Beispiel für Unit-Tests, da wir ihre Funktionsweise in zwei Szenarien überprüfen möchten. Übergeben wir zunächst zwei gewöhnliche Strings als Parameter, erwarten wir als Ergebnis einen String mit der SQL-Anweisung. Geben wir anschließend als zweiten Parameter einen String mit einer SQL-Injection an, erwarten wir, dass die Methode einen Fehler auslöst. Beide Fälle können wir mit einem Unit-Test überprüfen.

Zu Beginn müssen wir einige Maven-Pakete installieren, darunter das maven-surefire-plugin, das die JUnit-Bibliothek enthält. Außerdem müssen wir Maven mitteilen, dass unsere Anwendung beim Ausführen von Tests von JUnit abhängt.

Öffnen Sie die bereitgestellte Datei pom.xml und fügen Sie den folgenden Abhängigkeitscode im entsprechenden Abschnitt in Zeile 21 hinzu.

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.11</version>
  <scope>test</scope>
</dependency>

Speichern Sie die Datei anschließend.

Nun können wir Maven zum Installieren der Pakete verwenden. Öffnen Sie dazu in VSCode links unten das Menü Maven, klicken Sie mit der rechten Maustaste auf das Projekt und wählen Sie install. Wenn Sie eine andere IDE verwenden, kann dieser Vorgang anders aussehen.

Visual Studio Code zeigt die pom.xml eines Java-Projekts mit einer JUnit-4.11-Testabhängigkeit und geöffnetem Menü mit Maven-Befehlen

Wenn Sie nicht sicher sind, wie das in Ihrer IDE funktioniert, können Sie die Abhängigkeiten jederzeit über die Befehlszeile installieren. Wechseln Sie in einem Terminal in das Stammverzeichnis Ihres Projekts und führen Sie den folgenden Maven-Befehl aus, um die Abhängigkeiten zu installieren.

Hinweis: Wenn Maven noch nicht auf Ihrem Rechner installiert ist, befolgen Sie vor der Ausführung dieses Befehls die Installationsanleitung.

mvn install -f pom.xml

Nach Abschluss hat Maven die in unserer Datei pom.xml file angegebenen Plugins installiert, darunter die JUnit-Bibliothek. Beim Ausführen von Tests weiß Maven, dass JUnit verwendet werden soll, da wir es in der Konfiguration mit <scope>test</scope> als Testabhängigkeit definiert haben.

Terminalausgabe mit Java-Unit-Tests ohne Fehler und einem grünen Maven-Ergebnis „BUILD SUCCESS“.

Wie die obige Ausgabe zeigt, werden am Ende des Installationsvorgangs Informationen zu unseren Tests angezeigt. Da derzeit jedoch keine Tests konfiguriert sind, wurden 0 Tests ausgeführt. Ändern wir das, indem wir unserer Anwendung zwei Unit-Tests hinzufügen.

Öffnen Sie zunächst die Datei src/test/java/com/snyk/unittestdemo/AppTest.java, die Maven zum Ausführen unserer Tests verwendet. Zuerst müssen wir die benötigten JUnit-Pakete importieren. Fügen Sie die folgenden beiden Import-Anweisungen am Anfang der Datei ein:

import org.junit.Test;

import static org.junit.Assert.assertTrue;

Mit dem ersten Import erhalten wir Zugriff auf die JUnit-Testannotation, mit der wir unsere Methoden als Tests definieren können. Der zweite Import betrifft die von JUnit bereitgestellte Methode assertTrue. Mit dieser Methode prüfen wir, ob eine Bedingung wahr ist. Ist das der Fall, besteht der Test. Andernfalls schlägt er fehl.

Fügen wir unseren ersten Test hinzu. Er überprüft, ob unsere Methode generateUpdateUserFirstNameStatement bei zwei gewöhnlichen Strings das richtige Ergebnis zurückgibt. Fügen Sie dazu der Klasse AppTest die folgende Methode hinzu.

@Test
public void shouldGenerateUpdateStatement()
{
    String actual = App.generateUpdateUserFirstNameStatement("John", "abcdef1234567");
    String expected = "UPDATE TABLE user SET first_name = 'John' WHERE user_id = 'abcdef1234567';";
    assertTrue( actual.equals(expected) );
}

Mit der Annotation @Test haben wir die Methode als Test definiert. Anschließend haben wir die importierte Methode assertTrue verwendet, um die Ausgabe unserer Methode generateUpdateUserFirstNameStatement zu überprüfen. Wir haben die beiden Strings John und abcdef1234567 übergeben und möchten prüfen, ob die Funktion den erwarteten String zurückgibt. Wenn unsere Methode korrekt funktioniert, sollte dieser Test bestehen.

Speichern Sie die Datei und führen Sie den Test aus, um zu überprüfen, ob er besteht. In VSCode können Sie mit der rechten Maustaste auf das Maven-Projekt klicken und test auswählen.

Visual Studio Code zeigt eine Java-JUnit-AppTest-Datei und die Maven-Terminalausgabe mit einem erfolgreichen Test und einem erfolgreichen Build

Sie können diesen Befehl jederzeit im Terminal ausführen. Öffnen Sie dazu das Terminal, wechseln Sie in den Projektordner und führen Sie den folgenden Befehl aus.

mvn test -f pom.xml

Mit diesem Befehl weisen Sie Maven an, die Anwendung zu erstellen und die Tests auszuführen. In der Testausgabe sollte nun stehen, dass ein Test ausgeführt wurde und keine Fehler aufgetreten sind.

Terminalausgabe eines Java-Unit-Testlaufs ohne fehlgeschlagene, fehlerhafte oder übersprungene Tests, gefolgt von der Meldung BUILD SUCCESS.

Ändern wir nun die Methode generateUpdateUserFirstNameStatement leicht, indem wir die von der Funktion zurückgegebene UPDATE-Anweisung anpassen. Führen Sie die Tests erneut aus, um zu sehen, wie Maven einen Fehler anzeigt.

Terminalausgabe mit einem fehlgeschlagenen Java-Unit-Test: eine fehlgeschlagene Assertion in AppTest.shouldGenerateUpdateStatement und ein fehlgeschlagener Maven-Build.

Die Ausgabe ändert sich nun und zeigt an, dass ein Test fehlgeschlagen ist. Unter der Überschrift Results: sehen Sie die Anzahl und Art der Fehler. In diesem Fall werden in den Ergebnissen unsere Testmethode generateUpdateUserFirstNameStatement und die Zeilennummer des Fehlers (Zeile 14) angegeben. Denken Sie daran, die Änderungen rückgängig zu machen, durch die die Funktion beeinträchtigt wurde.

Wir können auch überprüfen, ob unsere Funktion wie vorgesehen einen Fehler auslöst. Dafür verwenden wir einen etwas anderen Ansatz als die Methode assertTrue. Fügen Sie zunächst die folgende Testmethode zur Testklasse hinzu.

@Test(expected = Error.class)
public void shouldThrowErrorForSQLInjection()
{
    App.generateUpdateUserFirstNameStatement("John", "abcdef1234567; DROP TABLE user;");
}

Hier haben wir die Annotation @Test verwendet, um einen erwarteten Wert anzugeben. Wir erwarten, dass unsere Methode eine Instanz der Klasse Error auslöst, da wir sie so programmiert haben, dass sie eine SQL-Injection in einem der beiden Parameter behandelt. Nun können wir die Tests ausführen und überprüfen, ob sie bestehen.

Terminalausgabe mit einem erfolgreichen Java-Unit-Testlauf: zwei Tests, keine Fehlschläge oder Fehler und die Meldung BUILD SUCCESS.

Wir haben erfolgreich unsere ersten Java-Unit-Tests mit JUnit implementiert. Damit können wir sicherstellen, dass unser Code wie erwartet funktioniert und die richtigen Ergebnisse liefert. Ist das nicht der Fall, schlägt unser Test fehl.

Es ist unerlässlich, unsere Anwendungen vor Sicherheitslücken zu schützen, etwa vor solchen, die uns bösartigen SQL-Injections aussetzen. Ein Test wie dieser kann verhindern, dass Entwickler diese Sicherheitslücke künftig einführen. Tests stärken unser Vertrauen in den Code und bieten zukünftigen Entwicklern ein Sicherheitsnetz. Hier erfahren Sie mehr über Best Practices für Java-Sicherheit.

Snyk Code ist ein weiteres Tool, das unsichere Programmierpraktiken erkennt, die Entwicklern möglicherweise nicht bewusst sind und für die keine Tests geschrieben wurden. Dazu gehört das Erkennen von Code, der für SQL-Injections anfällig ist, sowie von fest codierten vertraulichen Informationen wie API-Schlüsseln und personenbezogenen Daten.

Der Test legt fest, was die Methode leisten soll. Möchte ein Entwickler die Methode generateUpdateUserFirstNameStatement aktualisieren und macht sie dabei versehentlich kaputt – wie bei unserem zweiten Test –, schlägt der Unit-Test fehl und liefert Informationen zum Fehler. Diese Vorgehensweise bietet eine zusätzliche Schutzebene gegen den Verlust zentraler Funktionen sowie gegen die Freigabe instabiler oder gefährlicher Änderungen in einer Produktionsanwendung.

Fazit

Wie wir in diesem Tutorial erfahren haben, sind Unit-Tests eine einfache Möglichkeit, sicherzustellen, dass sich unser Code in beliebig vielen Szenarien wie vorgesehen verhält. Außerdem bieten Unit-Tests bei der Zusammenarbeit an Projekten eine zusätzliche Ebene der Fehlertoleranz: Sie verhindern, dass andere Entwickler unseren Code versehentlich beschädigen oder Sicherheitslücken einführen. Unit-Tests sind zwar längst nicht die einzige Methode zum Testen von Anwendungen, sollten aber zum Standardrepertoire aller Entwickler gehören.

Weitere technische Informationen zu Java finden Sie in diesen verwandten Artikeln:

Starten Sie mit Capture the Flag

Erfahren Sie in unserem virtuellen On-Demand-Workshop für Einsteiger, wie Sie Capture-the-Flag-Herausforderungen lösen.

Weiterlesen

Blog

Frontier-Modelle fanden die Schwachstellen. Nur der Angreifer fand die Angriffsketten.

Die statische Analyse fand die Schwachstellen, doch erst Live-Angriffstests bewiesen, wie sie sich zu Angriffen verketten lassen. Ein Vergleich von Evo COS, Claude Security und Claude Code Security.

feature insights context
Blog

Autonome Angriffe sind bereits Realität. Die Verteidigung muss Schritt halten.

Autonome Angreifer verkürzen das Zeitfenster für die Verteidigung. Erfahren Sie, wie kontinuierliches Erkennen, Beheben, Validieren und Verhindern Sicherheitsteams helfen kann, Schritt zu halten.

Blog

Warum KI-Coding-Agenten immer wieder fehlerhafte Zugriffskontrollen schreiben

KI-Coding-Agenten können Autorisierungslogik erzeugen, die kompiliert und die Prüfung besteht, dabei aber die Daten eines Mandanten für einen anderen offenlegt. Erfahren Sie, warum fehlerhafte Zugriffskontrollen schwer zu erkennen sind und wie Sie sie verhindern.