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.

33voto

rwitzel Punkte 1595

Um das gleiche Problem zu lösen, habe ich ein kleines Projekt eingerichtet: http://code.google.com/p/catch-exception/

Mit dieser kleinen Hilfe würden Sie schreiben

verifyException(foo, IndexOutOfBoundsException.class).doStuff();

Dies ist weniger ausführlich als die ExpectedException-Regel von JUnit 4.7. Im Vergleich zu der von skaffman angebotenen Lösung können Sie angeben, in welcher Codezeile Sie die Ausnahme erwarten. Ich hoffe, das hilft.

0 Stimmen

Ich dachte auch darüber nach, so etwas zu tun, entdeckte aber schließlich, dass die wahre Stärke von ExpectedException darin liegt, dass Sie nicht nur die erwartete Ausnahme angeben können, sondern auch bestimmte Eigenschaften der Ausnahme, wie die erwartete Ursache oder die erwartete Meldung, angeben können.

0 Stimmen

Meine Vermutung ist, dass diese Lösung einige der gleichen Nachteile wie Mocks hat? Zum Beispiel, wenn foo es final wird es scheitern, weil Sie keinen Proxy einsetzen können foo ?

0 Stimmen

Tom, wenn doStuff() Teil einer Schnittstelle ist, wird der Proxy-Ansatz funktionieren. Andernfalls wird dieser Ansatz scheitern, Sie haben Recht.

22voto

John Mikic Punkte 632

Sie können auch dies tun:

@Test
public void testFooThrowsIndexOutOfBoundsException() {
    try {
        foo.doStuff();
        assert false;
    } catch (IndexOutOfBoundsException e) {
        assert true;
    }
}

12 Stimmen

In JUnit-Tests ist es besser, die Assert.fail() , nicht assert nur für den Fall, dass Ihre Tests in einer Umgebung laufen, in der Assertions nicht aktiviert sind.

15voto

Alex Collins Punkte 1021

IMHO ist der beste Weg, um in JUnit auf Ausnahmen zu prüfen, das try/catch/fail/assert-Muster:

// this try block should be as small as possible,
// as you want to make sure you only catch exceptions from your code
try {
    sut.doThing();
    fail(); // fail if this does not throw any exception
} catch(MyException e) { // only catch the exception you expect,
                         // otherwise you may catch an exception for a dependency unexpectedly
    // a strong assertion on the message, 
    // in case the exception comes from anywhere an unexpected line of code,
    // especially important if your checking IllegalArgumentExceptions
    assertEquals("the message I get", e.getMessage()); 
}

El assertTrue könnte für einige Leute etwas zu stark sein, daher assertThat(e.getMessage(), containsString("the message"); könnte vorzuziehen sein.

14voto

Daniel Käfer Punkte 3910

JUnit 5 Lösung

@Test
void testFooThrowsIndexOutOfBoundsException() {    
  IndexOutOfBoundsException exception = expectThrows(IndexOutOfBoundsException.class, foo::doStuff);

  assertEquals("some message", exception.getMessage());
}

Mehr Infos über JUnit 5 auf http://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions

0 Stimmen

expectThrows() ist ein Teil von TestNG, nicht von JUnit

13voto

Dherik Punkte 15172

Die flexibelste und eleganteste Lösung für Junit 4 fand ich in der Mkyong-Blog . Es hat die Flexibilität des try/catch unter Verwendung der @Rule Bemerkung. Ich mag diesen Ansatz, weil Sie spezifische Attribute einer benutzerdefinierten Ausnahme lesen können.

package com.mkyong;

import com.mkyong.examples.CustomerService;
import com.mkyong.examples.exception.NameNotFoundException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.hasProperty;

public class Exception3Test {

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

    @Test
    public void testNameNotFoundException() throws NameNotFoundException {

        //test specific type of exception
        thrown.expect(NameNotFoundException.class);

        //test message
        thrown.expectMessage(is("Name is empty!"));

        //test detail
        thrown.expect(hasProperty("errCode"));  //make sure getters n setters are defined.
        thrown.expect(hasProperty("errCode", is(666)));

        CustomerService cust = new CustomerService();
        cust.findByName("");

    }

}

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