JUnit Erwarteter Ausnahmetest: @Test(erwartet)

⚡ Intelligente Zusammenfassung

JUnit Ausnahmetests bestätigen, dass eine Methode den Fehler auslöst, den sie auslösen soll, indem sie den optionalen erwarteten Parameter der @Test-Annotation verwenden. JUnit 4 und die assertThrows-Methode in JUnit 5.

  • 🔘 Zweck: Weisen Sie nach, dass eine ungültige Eingabe die dokumentierte Ausnahme und nicht eine stillschweigende falsche Antwort erzeugt.
  • ☑️ Syntax: @Test(expected = ArithmeticException.class) ist nur dann erfolgreich, wenn genau dieser Ausnahmetyp ausgelöst wird.
  • Ejemplo: JUnitDie Nachricht wird durch Null geteilt, und AirthematicTest erwartet die daraus resultierende ArithmeticException.
  • 🧪 Alternative: Ein try-Block gefolgt von fail() ermöglicht es Ihnen, die abgefangene Ausnahme zu untersuchen, bevor Sie eine Assertion durchführen.
  • JUnit 5: assertThrows gibt die abgefangene Ausnahme zurück, sodass auch die Meldung und die Ursache überprüft werden können.
  • 📌 Falle: Der erwartete Parameter wird überall dort übergeben, wo die Ausnahme auftritt, wodurch ein Fehler im Setup-Code verschleiert werden kann.

JUnit erwartete Ausnahmeprüfung mithilfe des Parameters @Test(expected)

JUnit bietet die Möglichkeit tracDie Ausnahme wird geprüft, und es wird auch überprüft, ob der Code die erwartete Ausnahme auslöst oder nicht.

JUnit 4 bietet eine einfache und übersichtliche Möglichkeit zum Testen von Ausnahmen. Sie können Folgendes verwenden:

  • Der optionale Parameter (erwartet) des @Test-Annotation und
  • Zu tracAus den Informationen kann „fail()“ verwendet werden.

Während testing Im Falle einer Ausnahme müssen Sie sicherstellen, dass die Ausnahmeklasse, die Sie in diesem optionalen Parameter angeben, korrekt ist. @Test-Annotation Es handelt sich um dieselbe Ausnahme, die die Methode tatsächlich auslöst. Das liegt daran, dass Sie von der Methode eine Ausnahme erwarten. Unit-Testandernfalls unser JUnit Der Test würde fehlschlagen.

Beispiel: @Test(expected = IllegalArgumentException.class)

Mithilfe des Parameters „expected“ können Sie den Namen der Ausnahme angeben, die unser Test auslösen kann. Im obigen Beispiel verwenden Sie „IllegalArgumentException“, was vom Test ausgelöst wird, wenn ein Entwickler ein nicht zulässiges Argument verwendet.

Beispiel mit @Test(expected)

Lassen Sie uns Ausnahmetests verstehen, indem wir ein Java Klasse mit einer Methode, die eine Ausnahme auslöst AusnahmeSie werden dies in einer Testklasse behandeln und testen. Beachten Sie Folgendes: JUnitDie Datei Message.java enthält eine Methode, die eine mathematische Operation ausführt. Die Division in Zeile 14 teilt durch Null, daher löst die Methode immer eine „ArithmeticException“ aus. Siehe unten:

JUnitNachrichtenklasse in Eclipse mit printMessage dividiert durch Null in Zeile 14

package guru99.junit;

public class JUnitMessage{

	private String message;

	public JUnitMessage(String message) {
		this.message = message;
	}

public void printMessage(){

	System.out.println(message); 
	int divide=1/0;

}

public String printHiMessage(){ 

	message="Hi!" + message;
	
	System.out.println(message);

	return message;
}

}

Code Erläuterung:

  • Code Linie 7: Erstellen eines parametrisierten Konstruktors mit Feldinitialisierung.
  • Code Zeile 11-14: Eine Methode für die mathematische Operation erstellen.
  • Code Linie 18: Erstellen einer weiteren Methode zum Drucken einer Nachricht.
  • Code Linie 20: Erstellen einer neuen Zeichenfolge zum Drucken einer Nachricht.
  • Code Linie 22: Die in Zeile 20 erstellte neue Nachricht wird ausgegeben.

Erstellen wir eine Testklasse für das Obige. Java Klasse zur Überprüfung der Ausnahme.

Nachfolgend finden Sie die Testklasse, die die von der obigen Methode ausgelöste Ausnahme (hier: ArithmeticException) testet. Java Klasse:

AirthematicTest.java

Der folgende Screenshot zeigt denselben Test im Editor, wobei die Datei unter dem Namen AirthematicTest1 gespeichert ist und der erwartete Parameter in Zeile 13 hervorgehoben ist:

AirthematicTest1-Klasse in Eclipse mit @Test(expected = ArithmeticException.class) hervorgehoben in Zeile 13

package guru99.junit;

import static org.junit.Assert.assertEquals;

import org.junit.Test;

public class AirthematicTest {

	public String message = "Saurabh";
	
	JUnitMessage junitMessage = new JUnitMessage(message);
	
	@Test(expected = ArithmeticException.class)
	public void testJUnitMessage(){

		System.out.println("Junit Message is printing ");
		junitMessage.printMessage();

	}

	@Test
	public void testJUnitHiMessage(){ 
		message="Hi!" + message;
		System.out.println("Junit Message is printing ");
		assertEquals(message, junitMessage.printHiMessage());
	
	}
}

Code Erläuterung:

  • Code Linie 13: Wir verwenden die @Test-Annotation, um unseren Test zu erstellen. Beim Ausführen der Methode der obigen Klasse wird eine mathematische Operation ausgeführt. Hier wird eine ArithmeticException erwartet, daher geben wir sie als Parameter in @Test an.
  • Code Linie 17: Aufruf von printMessage() von JUnitMessage.java.
  • Code Zeile 21-22: Es wird eine weitere Testmethode erstellt, um die Hi-Nachricht zu überprüfen, diesmal ohne einen erwarteten Parameter.

Die Klasse enthält zwei Testmethoden, sodass bei einem einzigen Durchlauf beide ausgeführt werden: diejenige, die eine ArithmeticException erwartet, und diejenige, die den zurückgegebenen String überprüft.

Hinweis: Dieses Beispiel wird im Originalmaterial unter drei verschiedenen Namen geführt: Im Listing heißt die Klasse „AirthematicTest“, im Screenshot des Editors „AirthematicTest1“ und in der Ergebnisansicht „JunitTestExample“. Der Code ist in allen Fällen identisch; lediglich der Dateiname unterscheidet sich.

Führen wir es aus und überprüfen wir das Ergebnis. JUnit Die unten stehenden Berichte zeigen den Ablauf von JunitTestExample.java.

Ausgang:

Hier ist die Ausgabe, die einen erfolgreichen Test ohne Fehler anzeigt. trace wie unten angegeben:

Eclipse JUnit Bericht anzeigen: 2 von 2 Läufen ohne Fehler und ohne Ausfälle für JUnitTestExample

Beide Methoden sind erfolgreich. Die erste Methode ist erfolgreich, weil die deklarierte ArithmeticException tatsächlich aufgetreten ist, und die zweite, weil der zurückgegebene String übereinstimmt. Wäre die Division nicht ausgelöst worden, JUnit Die erste Methode wäre mit der Meldung „Expected exception: java.lang.ArithmeticException“ fehlgeschlagen.

Drei Möglichkeiten, eine Ausnahme zu testen in JUnit 4

Der erwartete Parameter ist der kürzeste der drei. JUnit Es gibt vier Redewendungen, aber nicht immer ist die richtige die richtige. Die Tabelle vergleicht sie anhand der beiden Fragen, die die Wahl entscheiden: Können Sie die Aussage bestätigen, und wissen Sie, welche Formulierung verwendet wurde?

Ansatz Bestätigt die Nachricht? Fixiert die Wurfschnur? am besten für
@Test(expected = X.class) Nein Nein – jede Zeile in der Methode kann eine Ausnahme auslösen. Kurze Tests, bei denen nur der Ausnahmetyp relevant ist.
try / fail() / catch Ja, innerhalb des Fangblocks Ja – nur der überwachte Anruf wird beobachtet. Tests, die die Nachricht oder die Ursache untersuchen müssen.
@Rule ExpectedException Ja, über expectMessage() Nein Legacy-Suites, die bereits auf Regeln basieren.

Die in der Einleitung erwähnte fail()-Anweisung sieht folgendermaßen aus: Wenn der Aufruf keine Ausnahme auslöst, wird fail() ausgeführt und der Test meldet die von Ihnen verfasste Meldung:

@Test
public void testDivideByZero() {
    try {
        junitMessage.printMessage();
        fail("Expected an ArithmeticException");
    } catch (ArithmeticException e) {
        assertEquals("/ by zero", e.getMessage());
    }
}

Die ExpectedException-Regel steht dazwischen. Sie wurde in [Jahr einfügen] als veraltet markiert. JUnit 4.13 zugunsten der im Folgenden beschriebenen assertThrows-Methode, also neu JUnit 4 Tests sollten es nicht übernehmen.

Wie man Ausnahmen testet in JUnit 5 mit assertThrows()

JUnit 5 entfernt den erwarteten Parameter vollständig aus @Test. Jupiter liefert assertThrows ()Diese Funktion nimmt die Ausnahmeklasse und eine Lambda-Funktion entgegen, die den zu testenden Code enthält. Sie gibt die abgefangene Ausnahme zurück, sodass anschließend die Meldung, die Ursache und alle benutzerdefinierten Felder überprüft werden können.

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;

public class AirthematicJupiterTest {

    JUnitMessage junitMessage = new JUnitMessage("Saurabh");

    @Test
    public void testJUnitMessage() {
        ArithmeticException thrown = assertThrows(
                ArithmeticException.class,
                () -> junitMessage.printMessage());
        assertEquals("/ by zero", thrown.getMessage());
    }
}

Drei verwandte Behauptungen Vervollständigen Sie die Familie:

  • assertThrows Akzeptiert den Ausnahmetyp oder eine beliebige Unterklasse davon.
  • assertThrowsExactly Eine Unterklasse wird abgelehnt, daher wird nur der benannte Typ akzeptiert.
  • assertDoesNotThrow wird die gegenteilige Erwartung formuliert, nämlich dass der Block sauber abgeschlossen wird.

Das JUnit 4 Der Code auf dieser Seite läuft immer noch auf dem JUnit Die Plattform basiert auf der Vintage-Engine, sodass nichts davon neu geschrieben werden muss, um während der Migration eines Projekts weiterhin zu funktionieren.

Häufige Fehler beim Testen von Ausnahmen in JUnit

Ausnahmetests schlagen auf wenige, erkennbare Arten fehl. Jede Zeile benennt das Symptom, die Ursache und die Lösung.

Symptom Verursachen Fixieren
Erwartete Ausnahme: java.lang.ArithmeticException Die Methode wurde ohne Ausnahme abgeschlossen. Prüfen Sie, ob die Eingabe tatsächlich ungültig ist, und führen Sie den Vorgang dann erneut aus.
Der Test wurde bestanden, aber die falsche Zeile wurde ausgeworfen Der erwartete Parameter überwacht die gesamte Methode, einschließlich der Einrichtung. Verlagern Sie das Setup nach außen oder verwenden Sie assertThrows um einen Aufruf herum.
Unbehandelter Ausnahmetyp im Editor Es wird eine geprüfte Ausnahme ausgelöst, die jedoch nie deklariert wird. Füge der Signatur der Testmethode Ausnahmen hinzu.
Der Test ist für eine Unterklasse erfolgreich, die Sie nicht vorgesehen hatten. assertThrows akzeptiert Unterklassen des benannten Typs. Verwenden Sie assertThrowsExactly für einen strikten Typabgleich.
„expected“ ist kein gültiges Attribut. Der Test wurde anhand der Jupiter @Test-Annotation kompiliert. Importieren Sie org.junit.Test für JUnit 4, oder wechsle zu assertThrows.

Die letzte Zeile ist diejenige, die die meisten mitten in der Migration überrascht, da beide Annotationen @Test heißen und nur der Import sie unterscheidet. Keeping dank One JUnit Version pro Testfall Diese Klasse vermeidet das gesamte Problem.

Häufig gestellte Fragen

Der erwartete Parameter kann keine Nachricht prüfen. Schließen Sie den Aufruf in einen try-Block ein, rufen Sie direkt im Anschluss fail() auf und prüfen Sie getMessage() innerhalb des catch-Blocks. JUnit 5 vereinfacht dies, da assertThrows die abgefangene Ausnahme zurückgibt.

JUnit Der Test schlägt fehl und meldet „Erwartete Ausnahme“ gefolgt von der angegebenen Klasse. Es werden keine weiteren Meldungen ausgegeben, sodass ein Test, der keine Ausnahme auslöst, identisch aussieht wie ein Test, dessen Produktionscode das Verhalten stillschweigend geändert hat.

KI-Assistenten lesen eine Methode, listen die Eingaben auf, die zu jeder throw-Anweisung führen, und entwerfen einen Test pro Zweig. Die Ausgabe dient als Ausgangspunkt: Der Assistent leitet den Ausnahmetyp aus dem Code ab, sodass eine falsche throw-Anweisung korrekt in den Test übernommen wird.

Copilot Es wird der bereits im Projekt vorhandene Stil beibehalten, daher erhält ein gemischtes Projekt eine gemischte Version. Überprüfen Sie die Importzeile, bevor Sie einen Vorschlag annehmen, da org.junit.Test und org.junit.jupiter.api.Test im Editor identisch aussehen.

Es existiert noch, wurde aber in der Vergangenheit als veraltet eingestuft. JUnit 4.13 und wurde nie auf Jupiter portiert. Bestehende Testsuiten können sie beibehalten; neue Tests sollten assertThrows verwenden, da dies besser lesbar ist und kein öffentliches Regelfeld benötigt.

Ja. Der Lambda-Parameter ist ein Executable, das so deklariert ist, dass es eine Throwable-Ausnahme auslöst. Daher benötigt eine geprüfte Ausnahme keine throws-Klausel in der Testmethode selbst. Dasselbe gilt für die JUnit 4. Redewendung „versuchen und fangen“.

`assertThrows` akzeptiert jede Unterklasse des angegebenen Typs. Daher löst eine erwartete `RuntimeException` auch eine `NullPointerException` aus. Verwenden Sie `assertThrowsExactly`, wenn die genaue Klasse wichtig ist, oder geben Sie den kleinsten erwarteten Typ an.

Nur wenn die Ausnahme Teil der Vereinbarung isttract. Das Testen einer Ausnahme, bei der die Methode niemals verspricht, Sperren auszulösen, führt zu unbeabsichtigtem Verhalten und erschwert das Refactoring, was den Sinn des Tests zunichtemacht.

Fassen Sie diesen Beitrag mit folgenden Worten zusammen: