2296 Stimmen

Wie können Sie sicherstellen, dass eine bestimmte Ausnahme in JUnit 4-Tests ausgelöst wird?

Wie kann ich JUnit4 idiomatisch verwenden, um zu testen, dass ein Code eine Ausnahme auslöst?

Ich kann so etwas zwar durchaus machen:

@Test
public void testFooThrowsIndexOutOfBoundsException() {
  boolean thrown = false;

  try {
    foo.doStuff();
  } catch (IndexOutOfBoundsException e) {
    thrown = true;
  }

  assertTrue(thrown);
}

Ich erinnere mich, dass es eine Annotation oder eine Assert.xyz oder etwas die für diese Art von Situationen weit weniger plump und weit mehr im Geiste von JUnit ist.

27 Stimmen

Das Problem bei allen anderen Ansätzen ist, dass sie den Test immer beenden, sobald die Ausnahme ausgelöst wurde. Ich hingegen möchte oft noch org.mockito.Mockito.verify mit verschiedenen Parametern, um sicherzustellen, dass bestimmte Dinge geschehen (z. B. dass ein Logger-Dienst mit den richtigen Parametern aufgerufen wurde), bevor die Ausnahme ausgelöst wird.

5 Stimmen

Sie können sehen, wie man Ausnahmen Test in JUnit Wiki-Seite github.com/junit-team/junit/wiki/Exception-testing

6 Stimmen

@ZeroOne - Für das würde ich zwei verschiedene Tests haben - eine für die Ausnahme und eine, um die Interaktion mit Ihrem Mock zu überprüfen.

94voto

NamshubWriter Punkte 22785

Jetzt, da JUnit 5 und JUnit 4.13 veröffentlicht wurden, wäre die beste Option die Verwendung von Assertions.assertThrows() (für JUnit 5) und Assert.assertThrows() (für JUnit 4.13). Siehe die JUnit 5 Benutzerhandbuch .

Hier ist ein Beispiel, das überprüft, ob eine Ausnahme ausgelöst wurde, und das Folgendes verwendet Die Wahrheit um Behauptungen über die Ausnahmemeldung aufzustellen:

public class FooTest {
  @Test
  public void doStuffThrowsIndexOutOfBoundsException() {
    Foo foo = new Foo();

    IndexOutOfBoundsException e = assertThrows(
        IndexOutOfBoundsException.class, foo::doStuff);

    assertThat(e).hasMessageThat().contains("woops!");
  }
}

Die Vorteile gegenüber den Ansätzen in den anderen Antworten sind:

  1. Eingebaut in JUnit
  2. Sie erhalten eine nützliche Ausnahmemeldung, wenn der Code im Lambda keine Ausnahme auslöst, und einen Stacktrace, wenn er eine andere Ausnahme auslöst
  3. Kurz und bündig
  4. Ermöglicht die Durchführung von Tests nach dem Prinzip Anordnen-Handeln-Bewerten
  5. Sie können genau angeben, welchen Code Sie erwarten, um die Ausnahme auszulösen
  6. Sie müssen die erwartete Ausnahme nicht in der throws Klausel
  7. Sie können das Assertion Framework Ihrer Wahl verwenden, um Aussagen über die abgefangene Ausnahme zu machen

0 Stimmen

Dieser Ansatz ist sauber, aber ich sehe nicht, wie unser Test "Arrange-Act-Assert" folgen kann, da wir den "Act"-Teil in einen "assertThrow" einpacken müssen, der ein Assert ist.

0 Stimmen

@Clockwork Das lambda ist die "Handlung". Das Ziel von Arrange-Act-Assert ist es, den Code sauber und einfach (und damit leicht zu verstehen und zu pflegen) zu machen. Wie Sie gesagt haben, ist dieser Ansatz sauber.

0 Stimmen

Ich hatte immer noch gehofft, dass ich den Wurf und die Ausnahme am Ende des Tests im "assert"-Teil bestätigen könnte. Bei diesem Ansatz müssen Sie die Handlung in eine erste Behauptung verpacken, um sie zuerst abzufangen.

56voto

Dilini Rajapaksha Punkte 2360

Aktualisierung: JUnit5 hat eine Verbesserung für Ausnahmetests: assertThrows .

Das folgende Beispiel stammt aus: Junit 5 Benutzerhandbuch

@Test
void exceptionTesting() {
    IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
        throw new IllegalArgumentException("a message");
    });
    assertEquals("a message", exception.getMessage());
}

Ursprüngliche Antwort unter Verwendung von JUnit 4.

Es gibt mehrere Möglichkeiten zu testen, ob eine Ausnahme ausgelöst wurde. Ich habe in meinem Beitrag auch die folgenden Optionen besprochen Wie man gute Unit-Tests mit JUnit schreibt

Stellen Sie die expected Parameter @Test(expected = FileNotFoundException.class) .

@Test(expected = FileNotFoundException.class) 
public void testReadFile() { 
    myClass.readFile("test.txt");
}

Verwendung von try catch

public void testReadFile() { 
    try {
        myClass.readFile("test.txt");
        fail("Expected a FileNotFoundException to be thrown");
    } catch (FileNotFoundException e) {
        assertThat(e.getMessage(), is("The file test.txt does not exist!"));
    }

}

Prüfung mit ExpectedException Die Regel.

@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
public void testReadFile() throws FileNotFoundException {

    thrown.expect(FileNotFoundException.class);
    thrown.expectMessage(startsWith("The file test.txt"));
    myClass.readFile("test.txt");
}

Weitere Informationen über Ausnahmetests finden Sie unter JUnit4-Wiki für Ausnahmetests y bad.robot - Erwartete Ausnahmen JUnit-Regel .

46voto

Johan Punkte 1900

Wie wäre es damit: Fangen Sie eine sehr allgemeine Ausnahme ab, stellen Sie sicher, dass sie es aus dem Catch-Block heraus schafft, und behaupten Sie dann, dass die Klasse der Ausnahme so ist, wie Sie es erwarten. Diese Behauptung wird fehlschlagen, wenn a) die Ausnahme vom falschen Typ ist (z.B. wenn Sie stattdessen einen Null-Zeiger erhalten haben) und b) die Ausnahme nie ausgelöst wurde.

public void testFooThrowsIndexOutOfBoundsException() {
  Throwable e = null;

  try {
    foo.doStuff();
  } catch (Throwable ex) {
    e = ex;
  }

  assertTrue(e instanceof IndexOutOfBoundsException);
}

4 Stimmen

Außerdem werden Sie nicht sehen, welche Art von Ausnahme in den Testergebnissen enthalten ist, wenn der Tag kommt, an dem der Test fehlschlägt.

1 Stimmen

Dies kann etwas verbessert werden, indem man die Art und Weise, wie man am Ende behauptet, ändert. assertEquals(ExpectedException.class, e.getClass()) zeigt Ihnen die erwarteten und tatsächlichen Werte, wenn der Test fehlschlägt.

42voto

weston Punkte 52445

Die Verwendung eines AssertJ Assertion, die zusammen mit JUnit verwendet werden kann:

import static org.assertj.core.api.Assertions.*;

@Test
public void testFooThrowsIndexOutOfBoundsException() {
  Foo foo = new Foo();

  assertThatThrownBy(() -> foo.doStuff())
        .isInstanceOf(IndexOutOfBoundsException.class);
}

Es ist besser als @Test(expected=IndexOutOfBoundsException.class) weil es garantiert, dass die erwartete Zeile im Test die Ausnahme ausgelöst hat, und weil es einfacher ist, mehr Details über die Ausnahme zu überprüfen, z. B. die Meldung:

assertThatThrownBy(() ->
       {
         throw new Exception("boom!");
       })
    .isInstanceOf(Exception.class)
    .hasMessageContaining("boom");

Maven/Gradle-Anweisungen hier.

0 Stimmen

Prägnanteste Weg und niemand schätzt es, seltsam. Ich habe nur ein Problem mit der assertJ-Bibliothek, assertThat Konflikte name-wise mit junit's. mehr über assertJ throwby: JUnit: Testen von Ausnahmen mit Java 8 und AssertJ 3.0.0 ~ Codeleak.pl

0 Stimmen

@ycomp Nun, es ist eine neue Antwort auf eine sehr alte Frage, also ist der Punkteunterschied trügerisch.

0 Stimmen

Das ist wahrscheinlich die beste Lösung, wenn man Java 8 und AssertJ verwenden kann!

39voto

MariuszS Punkte 29175

BDD Stil-Lösung: JUnit 4 + Auffangen von Ausnahmen + AssertJ

import static com.googlecode.catchexception.apis.BDDCatchException.*;

@Test
public void testFooThrowsIndexOutOfBoundsException() {

    when(() -> foo.doStuff());

    then(caughtException()).isInstanceOf(IndexOutOfBoundsException.class);

}

Abhängigkeiten

eu.codearte.catch-exception:catch-exception:2.0

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X