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.

2563voto

skaffman Punkte 389758

Das hängt von der JUnit-Version ab und davon, welche Assert-Bibliotheken Sie verwenden.

Die ursprüngliche Antwort für JUnit <= 4.12 war:

@Test(expected = IndexOutOfBoundsException.class)
public void testIndexOutOfBoundsException() {

    ArrayList emptyList = new ArrayList();
    Object o = emptyList.get(0);

}

Obwohl die Antwort https://stackoverflow.com/a/31826781/2986984 hat mehr Optionen für JUnit <= 4.12.

Hinweis :

78 Stimmen

Dieses Codestück wird nicht funktionieren, wenn Sie eine Ausnahme nur irgendwo in Ihrem Code erwarten, und nicht eine pauschale wie diese.

5 Stimmen

@skaffman Dies würde nicht mit org.junit.experimental.theories.Theory funktionieren, das von org.junit.experimental.theories.Theories ausgeführt wird.

0 Stimmen

@skaffman: Gibt es eine Möglichkeit, etwas Ähnliches zu tun in junit 3.8 erwarten, dass die Methode eine Ausnahme auslöst?

1443voto

NamshubWriter Punkte 22785

Edit : 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 meine andere Antwort für Einzelheiten.

Wenn Sie nicht auf JUnit 5 migriert haben, aber JUnit 4.7 verwenden können, können Sie die ExpectedException Die Regel:

public class FooTest {
  @Rule
  public final ExpectedException exception = ExpectedException.none();

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

    exception.expect(IndexOutOfBoundsException.class);
    foo.doStuff();
  }
}

Dies ist viel besser als @Test(expected=IndexOutOfBoundsException.class) denn der Test wird fehlschlagen, wenn IndexOutOfBoundsException geworfen wird, bevor foo.doStuff()

Ver dieser Artikel für Einzelheiten.

17 Stimmen

@skaffman - Wenn ich das richtig verstanden habe, sieht es so aus, als ob die exception.expect nur innerhalb eines Tests angewendet wird, nicht für die gesamte Klasse.

5 Stimmen

Wenn die erwartete Ausnahme eine geprüfte Ausnahme ist, sollten wir throws oder try-catch hinzufügen oder diese Situation auf andere Weise testen?

1 Stimmen

IMHO ist die Antwort von rwoo unten ist eine viel bessere Lösung ( code.google.com/p/catch-exception ), d.h. in diesem Beispiel, wenn Sie throw new NullPointerException(); nach foo.doStuff() wird der Test no mit einer NPE fehlschlagen.

506voto

daveb Punkte 70025

Seien Sie vorsichtig bei der Verwendung der erwarteten Ausnahme, da diese nur behauptet, dass die Methode hat diese Ausnahme ausgelöst, nicht eine bestimmte Code-Zeile im Test.

Ich neige dazu, dies zum Testen der Parametervalidierung zu verwenden, da solche Methoden in der Regel sehr einfach sind, aber komplexere Tests sind vielleicht besser geeignet:

try {
    methodThatShouldThrow();
    fail( "My method didn't throw when I expected it to" );
} catch (MyException expectedException) {
}

Urteilsvermögen anwenden.

111 Stimmen

Vielleicht bin ich zu altmodisch, aber ich bevorzuge das immer noch. Es gibt mir auch einen Platz, um die Ausnahme selbst zu testen: Manchmal habe ich Ausnahmen mit Gettern für bestimmte Werte, oder ich könnte einfach nach einem bestimmten Wert in der Nachricht suchen (z.B. nach "xyz" in der Nachricht "unrecognized code 'xyz'").

3 Stimmen

Ich denke, der Ansatz von NamshubWriter bietet Ihnen das Beste aus beiden Welten.

0 Stimmen

+1 nützlich in einigen Szenarien, in denen erwartet = xx nicht den Anforderungen entspricht.

245voto

walsh Punkte 2641

In Junit gibt es vier Möglichkeiten, Ausnahmen zu testen.

junit5.x

  • für junit5.x können Sie verwenden assertThrows wie folgt

    @Test
    public void testFooThrowsIndexOutOfBoundsException() {
        Throwable exception = assertThrows(IndexOutOfBoundsException.class, () -> foo.doStuff());
        assertEquals("expected messages", exception.getMessage());
    }

junit4.x

  • für junit4.x das optionale Attribut "expected" der Testanmeldung verwenden

    @Test(expected = IndexOutOfBoundsException.class)
    public void testFooThrowsIndexOutOfBoundsException() {
        foo.doStuff();
    }
  • für junit4.x verwenden Sie die ExpectedException-Regel

    public class XxxTest {
        @Rule
        public ExpectedException thrown = ExpectedException.none();
    
        @Test
        public void testFooThrowsIndexOutOfBoundsException() {
            thrown.expect(IndexOutOfBoundsException.class)
            //you can test the exception message like
            thrown.expectMessage("expected messages");
            foo.doStuff();
        }
    }
  • Sie können auch die klassische Try/Catch-Methode verwenden, die im Rahmen von Junit 3 weit verbreitet ist

    @Test
    public void testFooThrowsIndexOutOfBoundsException() {
        try {
            foo.doStuff();
            fail("expected exception was not occured.");
        } catch(IndexOutOfBoundsException e) {
            //if execution reaches here, 
            //it indicates this exception was occured.
            //so we need not handle it.
        }
    }
  • also

    • Wenn Sie Junit 5 mögen, dann sollten Sie auch das 1.
    • die 2. Möglichkeit wird verwendet, wenn Sie nur die Art der Ausnahme testen wollen
    • die ersten beiden werden verwendet, wenn Sie eine weitere Testausnahmemeldung wünschen
    • wenn Sie Junit 3 verwenden, dann ist die 4.
  • Für weitere Informationen können Sie lesen dieses Dokument y junit5-Benutzerhandbuch für Einzelheiten.

12 Stimmen

Für mich ist dies die beste Antwort, sie deckt alle Möglichkeiten sehr deutlich ab, danke! Ich persönlich verwende die 3. Option auch mit Junit4 aus Gründen der Lesbarkeit weiter, um einen leeren catch-Block zu vermeiden, kann man auch Throwable fangen und den Typ von e bestätigen

0 Stimmen

Ist es möglich, ExpectedException zu verwenden, um geprüfte Ausnahme zu erwarten?

0 Stimmen

Es handelt sich lediglich um eine Zusammenstellung der drei wichtigsten Antworten. IMO hätte diese Antwort gar nicht gepostet werden sollen, wenn sie nichts Neues bringt. Sie beantwortet nur (eine beliebte Frage) für die Vertreter. Ziemlich nutzlos.

223voto

Rafal Borowiec Punkte 4894

Wie bereits erwähnt, gibt es viele Möglichkeiten, mit Ausnahmen in JUnit umzugehen. Aber mit Java 8 gibt es eine weitere Möglichkeit: die Verwendung von Lambda-Ausdrücken. Mit Lambda-Ausdrücken können wir eine Syntax wie diese erreichen:

@Test
public void verifiesTypeAndMessage() {
    assertThrown(new DummyService()::someMethod)
            .isInstanceOf(RuntimeException.class)
            .hasMessage("Runtime exception occurred")
            .hasMessageStartingWith("Runtime")
            .hasMessageEndingWith("occurred")
            .hasMessageContaining("exception")
            .hasNoCause();
}

assertThrown akzeptiert eine funktionale Schnittstelle, deren Instanzen mit Lambda-Ausdrücken, Methodenreferenzen oder Konstruktorreferenzen erstellt werden können. assertThrown, das diese Schnittstelle akzeptiert, erwartet eine Ausnahme und ist bereit, diese zu behandeln.

Dies ist eine relativ einfache, aber wirkungsvolle Technik.

Schauen Sie sich diesen Blogbeitrag an, in dem diese Technik beschrieben wird: http://blog.codeleak.pl/2014/07/junit-testing-exception-with-java-8-and-lambda-expressions.html

Der Quellcode ist hier zu finden: https://github.com/kolorobot/unit-testing-demo/tree/master/src/test/java/com/github/kolorobot/exceptions/java8

Offenlegung: Ich bin der Autor des Blogs und des Projekts.

2 Stimmen

Ich mag diese Lösung, aber kann ich dies von einem Maven Repo herunterladen?

0 Stimmen

@Airduster eine Implementierung dieser Idee, die auf Maven verfügbar ist, ist stefanbirkner.github.io/vallado

6 Stimmen

@CristianoFontes eine einfachere Version dieser API ist für JUnit 4.13 geplant. Siehe github.com/junit-team/junit/commit/

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