Frage

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

Während ich so etwas wie dies sicherlich tun können:

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

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

  assertTrue(thrown);
}

Ich erinnere mich, dass es eine Anmerkung oder eine Assert.xyz oder etwas , die weit weniger kludgy und weit mehr in-the-Geist von JUnit für diese Art von Situationen sind.

War es hilfreich?

Lösung

JUnit 4 hat die Unterstützung für diese:

@Test(expected = IndexOutOfBoundsException.class)
public void testIndexOutOfBoundsException() {
    ArrayList emptyList = new ArrayList();
    Object o = emptyList.get(0);
}

Referenz: https://junit.org/junit4/faq.html#atests_7

Andere Tipps

Bearbeiten Nun, da JUnit5 freigegeben hat, wäre die beste Option sein Assertions.assertThrows() zu verwenden (siehe ).

Wenn Sie JUnit 5 nicht migriert haben, kann aber JUnit 4.7 verwenden, können Sie verwenden, um die ExpectedException 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();
  }
}

Das ist viel besser als @Test(expected=IndexOutOfBoundsException.class) weil der Test fehl, wenn IndexOutOfBoundsException vor foo.doStuff() geworfen

Siehe dieser Artikel Details

Seien Sie vorsichtig erwartete Ausnahme verwenden, weil sie behauptet nur, dass die Methode , dass die Ausnahme ausgelöst hat, nicht ein bestimmte Codezeile im Test.

Ich neige dazu, diese Prüfung für die Prüfung Parameter zu verwenden, da solche Verfahren in der Regel sehr einfach sind, aber komplexere Tests könnten besser bedient werden:

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

Anwenden Urteil.

Wie bereits beantwortet, gibt es viele Möglichkeiten, mit Ausnahmen in JUnit zu tun. Aber mit Java 8 ist ein anderes: mit Lambda-Ausdrücke. Mit Lambda-Ausdrücke können wir eine Syntax wie folgt erreicht werden:

@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, Instanzen, deren mit Lambda-Ausdrücke, Methode Referenzen oder Konstruktor Referenzen erstellt werden. assertThrown diese Schnittstelle akzeptieren wird erwarten und bereit sein, eine Ausnahme zu behandeln.

Dies ist relativ einfach, aber leistungsfähige Technik.

Haben Sie einen Blick auf diesen Blog-Eintrag beschreibt diese Technik: http://blog.codeleak.pl/2014/07/junit-testing-exception-with-java-8-and-lambda-expressions.html

Der Quellcode kann hier gefunden werden: https://github.com/kolorobot/unit-testing-demo/tree/master/src/test/java/com/github/kolorobot/exceptions/java8

Disclosure:. Ich bin der Autor des Blogs und das Projekt

in junit gibt es vier Möglichkeiten Ausnahme zu testen.

  • für junit4.x, verwenden Sie das optionale 'erwartete' Attribut-Test annonation

    @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 Art und Weise verwendet, weit unter junit 3 Framework verwenden

    @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.
        }
    }
    
  • schließlich für junit5.x, können Sie auch assertThrows wie folgt

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

    • die erste Art und Weise verwendet, wenn Sie nur die Art der Ausnahme testen
    • die anderen drei Arten verwendet werden, wenn Sie Testausnahmemeldung weiter wollen
    • Wenn Sie junit 3 betrieben werden, dann ist die dritte eine bevorzugt
    • , wenn Sie junit mögen 5, dann sollten Sie die 4. ein mögen
  • für weitere Informationen, können Sie diesem Dokument lesen und junit5 Bedienungsanleitung .

tl; dr

  • pre-JDK8: Ich werde den alten guten try-catch Block empfehlen. ( Vergessen Sie nicht, eine fail() Behauptung vor dem catch Block hinzufügen)

  • post-JDK8. Verwenden AssertJ oder benutzerdefinierte lambdas behaupten außergewöhnliche Verhalten

Unabhängig von JUnit 4 oder JUnit 5.

die lange Geschichte

Es ist möglich, sich selbst zu schreiben, eine do it yourself try-catch Block oder verwenden Sie die JUnit-Tools (@Test(expected = ...) oder die @Rule ExpectedException JUnit Regel Funktion).

Aber diese Art und Weise ist nicht so elegant und mischt nicht gut Lesbarkeit wiese mit anderen Werkzeugen. Außerdem JUnit Tooling einige Tücken haben.

  1. Die try-catch Block Sie den Block um das getestete Verhalten zu schreiben, und die Behauptung in dem catch-Block zu schreiben, die viele in Ordnung sein können, aber diese Art finden taht unterbricht den Lesefluss eines Tests. Darüber hinaus müssen Sie eine Assert.fail am Ende des try Block schreiben, da sonst der Test eine Seite der Behauptungen verpassen kann; PMD findbugs oder Sonar werden solche Probleme erkennen.

  2. Die @Test(expected = ...) Funktion ist interessant, wie Sie weniger Code schreiben und diesen Test dann schreiben, ist angeblich weniger anfällig Fehler Codierung. Aber ths Ansatz ein, einige Bereiche fehlt.

    • Wenn der Test auf der Ausnahme, wie die Ursache zusätzliche Dinge überprüfen muß oder die Nachricht (gut Ausnahmemeldungen wirklich wichtig sind, möglicherweise nicht ausreicht, um einen genauen Ausnahmetyp aufweist).
    • Auch als die Erwartung gesetzt wird um die in dem Verfahren, je nachdem, wie der getesteten Code dann die Ausnahme werfen kann der falsche Teil des Testcode geschrieben wird, was zu falsch positivem Test und ich bin nicht sicher, dass < em> PMD findbugs oder Sonar Hinweise auf einen solchen Code geben.

      @Test(expected = WantedException.class)
      public void call2_should_throw_a_WantedException__not_call1() {
          // init tested
          tested.call1(); // may throw a WantedException
      
          // call to be actually tested
          tested.call2(); // the call that is supposed to raise an exception
      }
      
  3. Die ExpectedException Regel ist auch ein Versuch, die bisherigen Einschränkungen zu beheben, aber es fühlt sich ein wenig umständlich zu bedienen, da es eine Erwartung Stil verwendet, EasyMock Benutzer kennt diesen Stil sehr gut. Es könnte für einige bequem sein, aber wenn Sie folgen Verhalten Driven Development (BDD) oder Anordnen Act Assert (AAA) Grundsätze für die ExpectedException Regel nicht in den Schreibstil passen . Abgesehen von, dass sie aus dem gleichen Problem leiden können wie die als @Test Art und Weise, je nachdem, wo Sie die Erwartung stellen.

    @Rule ExpectedException thrown = ExpectedException.none()
    
    @Test
    public void call2_should_throw_a_WantedException__not_call1() {
        // expectations
        thrown.expect(WantedException.class);
        thrown.expectMessage("boom");
    
        // init tested
        tested.call1(); // may throw a WantedException
    
        // call to be actually tested
        tested.call2(); // the call that is supposed to raise an exception
    }
    

    Auch die erwartete Ausnahme vor der Test-Anweisung gesetzt wird, es bricht Ihren Lesefluss, wenn die Tests BDD oder AAA folgen.

    Auch dieses Ausgabe auf JUnit des Autors Kommentar von ExpectedException. JUnit 4.13-beta-2 deprecates auch diesen Mechanismus:

      

    Anfrage Pull # 1519 : deprecate ExpectedException

         

    Die Methode Assert.assertThrows bietet eine schönere Art und Weise Ausnahmen für die Überprüfung. Darüber hinaus ist die Verwendung von ExpectedException fehleranfällig, wenn sie mit anderen Regeln wie TestWatcher weil die Reihenfolge der Regeln in diesem Fall wichtig ist, verwendet wird.

So sind diese oben genannten Optionen haben alle ihre Last von Einsprüche und eindeutig nicht immun gegen Coder Fehler.

  1. Es ist ein Projekt, das ich nach der Erstellung dieser Antwort bewusst wurde, die vielversprechend aussieht, ist es Fang -exception .

    Da die Beschreibung des Projekts, sagt, es ist ein Coder Schreib in einer fließenden Linie des Codes lassen fangendie Ausnahme und bietet diese Ausnahme für die spätere Behauptung. Und Sie können jede Behauptung Bibliothek verwenden wie hamcrest oder AssertJ .

    Ein schnelles Beispiel von der Homepage genommen:

    // given: an empty list
    List myList = new ArrayList();
    
    // when: we try to get the first element of the list
    when(myList).get(1);
    
    // then: we expect an IndexOutOfBoundsException
    then(caughtException())
            .isInstanceOf(IndexOutOfBoundsException.class)
            .hasMessage("Index: 1, Size: 0") 
            .hasNoCause();
    

    Wie Sie den Code sehen kann wirklich einfach ist, können Sie die Ausnahme in einer bestimmten Zeile zu fangen, die then API ist ein Alias, die AssertJ APIs (ähnlich mit assertThat(ex).hasNoCause()...) verwenden. An einem gewissen Punkt das Projekt verlassen FEST-Behaupten die Vorfahren des AssertJ . EDIT:. Es scheint das Projekt eine Java 8 Lambdas Unterstützung brauen

    Derzeit wird diese Bibliothek hat zwei Nachteile:

    • Zum Zeitpunkt des Schreibens dieses Artikels ist es bemerkenswert, diese Bibliothek zu sagen, auf Mockito 1.x basiert, wie es ein Modell des getesteten Objekts hinter der Szene erzeugt. Wie Mockito ist noch nicht aktualisiert diese Bibliothek nicht mit dem endgültigen Klassen oder endgültigen Methoden funktioniert . Und selbst wenn es auf Mockito 2 in der aktuellen Version basiert, würde dies einen globalen Mock-Hersteller (inline-mock-maker) zu erklären, etwas, das nicht, was Sie wollen, da dies mockmaker verschiedene Nachteile hat, dass die regelmäßigen mockmaker.

    • Es erfordert noch einen weiteren Test Abhängigkeit.

    Diese Fragen werden nicht zur Anwendung, wenn die Bibliothek lambdas unterstützen wird, jedoch wird die Funktionalität durch AssertJ Toolset dupliziert werden.

    alle Berücksichtigung, wenn Sie die catch-Ausnahme-Tool nicht verwenden möchten, ich werde die gute alte Art und Weise des try-catch Block, zumindest bis zum JDK7 empfehlen. Und für JDK 8 Benutzer Sie könnten es vorziehen, AssertJ zu verwenden, wie es kann mehr als nur behaupten Ausnahmen bieten.

  2. Mit dem JDK8, lambdas die Testszene betreten, und sie haben sich als eine interessante Möglichkeit sein außergewöhnliches Verhalten geltend zu machen. AssertJ wurde ein schönes fließend API zu behaupten außergewöhnliches Verhalten zu schaffen aktualisiert.

    Und ein Beispieltest mit AssertJ :

    @Test
    public void test_exception_approach_1() {
        ...
        assertThatExceptionOfType(IOException.class)
                .isThrownBy(() -> someBadIOOperation())
                .withMessage("boom!"); 
    }
    
    @Test
    public void test_exception_approach_2() {
        ...
        assertThatThrownBy(() -> someBadIOOperation())
                .isInstanceOf(Exception.class)
                .hasMessageContaining("boom");
    }
    
    @Test
    public void test_exception_approach_3() {
        ...
        // when
        Throwable thrown = catchThrowable(() -> someBadIOOperation());
    
        // then
        assertThat(thrown).isInstanceOf(Exception.class)
                          .hasMessageContaining("boom");
    }
    
  3. Mit einem nahezu vollständigen Umschreiben von JUnit 5, Behauptungen haben ein wenig verbessert, können sie interessant erweisen als ein aus dem Kasten heraus Art und Weise richtig Ausnahme geltend zu machen. Aber wirklich die Behauptung API ist immer noch ein bisschen schlecht, gibt es nichts außerhalb assertThrows .

    @Test
    @DisplayName("throws EmptyStackException when peeked")
    void throwsExceptionWhenPeeked() {
        Throwable t = assertThrows(EmptyStackException.class, () -> stack.peek());
    
        Assertions.assertEquals("...", t.getMessage());
    }
    

    Wie Sie assertEquals bemerkt noch void zurückkehrt, und als solche erlaubt keine Aussagen wie AssertJ verketten.

    Auch wenn Sie Namen Zusammenstoß mit Matcher oder Assert erinnern, vorbereitet werden, um den gleichen Zusammenstoß mit Assertions gerecht zu werden.

Ich mag, dass heute abzuschließen (2017.03.03) AssertJ 's einfache Bedienung, Erkennbar API, schnelles Tempo der Entwicklung und als de facto Testabhängigkeit ist die beste Lösung mit JDK8 unabhängig von dem Test-Framework (JUnit oder nicht), sollte vor JDKs stattdessen verlassen try-catch Blöcke, auch wenn sie klobig fühlen.

Diese Antwort wurde von eine andere Frage kopiert wurde, die die gleiche Sicht nicht haben, ich bin der selber Autor.

Nun, da JUnit 5 freigegeben, ist die beste Option Assertions.assertThrows() verwenden (siehe die Junit 5 Benutzerhandbuch ).

Hier ist ein Beispiel, das eine Ausnahme überprüft wird geworfen, und verwendet Wahrheit machen Aussagen über die Ausnahmemeldung:

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. erhalten Sie eine nützliche Ausnahmemeldung, wenn der Code in dem Lambda keine Ausnahme werfen, und einen Stacktrace, wenn es eine andere Ausnahme
  3. wirft
  4. Concise
  5. Ermöglicht die Tests anordnen-Act-Assert zu folgen
  6. Sie können genau angeben, welche Code, den Sie erwarten, dass die Ausnahme werfen
  7. Sie brauchen nicht die erwartete Ausnahme in der throws Klausel zur Liste
  8. Sie können die Behauptung Rahmen Ihrer Wahl verwenden Aussagen über die abgefangene Ausnahme zu machen

Ein ähnliches Verfahren wird hinzugefügt in JUnit 4,13 bis org.junit Assert.

Wie wäre es damit: eine sehr allgemeine Ausnahme fangen, stellen sicher, dass es es aus dem catch-Block macht, behaupten dann, dass die Klasse der Ausnahme ist, was Sie es erwarten. Diese Assertion wird scheitern, wenn a) die Ausnahme vom falschen Typ ist (z. B. wenn Sie einen Null-Zeiger statt) bekommen und b) die Ausnahme nicht immer geworfen.

public void testFooThrowsIndexOutOfBoundsException() {
  Throwable e = null;

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

  assertTrue(e instanceof IndexOutOfBoundsException);
}

BDD Stil Lösung: JUnit 4 + Fang Exception + AssertJ

@Test
public void testFooThrowsIndexOutOfBoundsException() {

    when(foo).doStuff();

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

}

Quellcode

Abhängigkeiten

eu.codearte.catch-exception:catch-exception:1.3.3

Unter Verwendung eine AssertJ Behauptung, die neben 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 die erwartete Linie im Test garantiert die Ausnahme ausgelöst hat und lässt Sie mehr Details über die Ausnahme, wie Nachricht überprüfen, einfacher:

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

Maven / Gradle Anweisungen hier.

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

Mit diesem kleinen Helfer 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 Lösung von skaffman vorgesehen ist, können Sie in dem Codezeile geben Sie die Ausnahme erwarten. Ich hoffe, das hilft.

Update: JUnit5 eine Verbesserung für Ausnahmen Tests hat. assertThrows

Beispiel finden Sie von: Junit 5 Benutzerhandbuch

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

Original Antwort mit JUnit 4.

Es gibt mehr Möglichkeiten zu testen, ob eine Ausnahme ausgelöst wird. Ich habe diskutiert auch die folgenden Optionen in meinem Beitrag Wie groß Unit-Tests mit JUnit schreiben

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

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

Mit 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!"));
    }

}

Test mit ExpectedException 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");
}

Sie können mehr über Ausnahmen Tests in JUnit4 Wiki für Exception Test lesen und bad.robot - Expecting Ausnahmen JUnit Regel .

Sie können dies auch tun:

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

IMHO, der beste Weg für Ausnahmen in JUnit zu überprüfen, ist die try / catch / Fail / behauptet 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()); 
}

Die assertTrue vielleicht ein bisschen stark für einige Leute sein, so assertThat(e.getMessage(), containsString("the message"); könnte vorzuziehen sein.

JUnit 5 Lösung

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

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

Mehr Infos über JUnit 5 auf http://junit.org/junit5/ docs / Strom / user-guide / # writing-Tests-Behauptungen

Ich habe versucht, viele der Methoden, die hier, aber sie waren entweder kompliziert oder nicht ganz meine Anforderungen erfüllen. In der Tat kann man eine Hilfsmethode schreibt ganz einfach:

public class ExceptionAssertions {
    public static void assertException(BlastContainer blastContainer ) {
        boolean caughtException = false;
        try {
            blastContainer.test();
        } catch( Exception e ) {
            caughtException = true;
        }
        if( !caughtException ) {
            throw new AssertionFailedError("exception expected to be thrown, but was not");
        }
    }
    public static interface BlastContainer {
        public void test() throws Exception;
    }
}

Verwenden Sie es wie folgt aus:

assertException(new BlastContainer() {
    @Override
    public void test() throws Exception {
        doSomethingThatShouldExceptHere();
    }
});

Null Abhängigkeiten: keine Notwendigkeit für Mockito, keine Notwendigkeit PowerMock; und funktioniert gut mit finalen Klassen.

Die flexibelste und elegante Lösung für JUnit 4 I in der Mkyong Blog . Es hat die Flexibilität des try/catch die @Rule Anmerkung verwenden. Ich mag diesen Ansatz, weil Sie bestimmte Attribute einer angepassten Ausnahme lesen kann.

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("");

    }

}

Java 8-Lösung

Wenn Sie eine Lösung wie, welche:

  • Nutzt Java 8 lambdas
  • Does nicht hängt von jeder JUnit Magie
  • Hier können Sie für mehrere Ausnahmen innerhalb eines einzigen Testverfahren überprüfen
  • Prüft, ob eine Ausnahme von einer bestimmten Gruppe von Linien in Ihrem Testverfahren im gesamten Testverfahren anstelle einer unbekannten Linie geworfen
  • Liefert das aktuelle Ausnahmeobjekt, die ausgelöst wurde, so dass Sie es weiter untersuchen

Hier ist eine Nutzenfunktion, die ich schrieb:

public final <T extends Throwable> T expectException( Class<T> exceptionClass, Runnable runnable )
{
    try
    {
        runnable.run();
    }
    catch( Throwable throwable )
    {
        if( throwable instanceof AssertionError && throwable.getCause() != null )
            throwable = throwable.getCause(); //allows "assert x != null : new IllegalArgumentException();"
        assert exceptionClass.isInstance( throwable ) : throwable; //exception of the wrong kind was thrown.
        assert throwable.getClass() == exceptionClass : throwable; //exception thrown was a subclass, but not the exact class, expected.
        @SuppressWarnings( "unchecked" )
        T result = (T)throwable;
        return result;
    }
    assert false; //expected exception was not thrown.
    return null; //to keep the compiler happy.
}

( aus meinem Blog genommen)

Verwenden Sie es wie folgt:

@Test
public void testThrows()
{
    RuntimeException e = expectException( RuntimeException.class, () -> 
        {
            throw new RuntimeException( "fail!" );
        } );
    assert e.getMessage().equals( "fail!" );
}

JUnit hat eine eingebaute Unterstützung für diese, mit einem „erwartet“ Attribute

In meinem Fall habe ich immer Runtime von db, aber Nachrichten unterscheiden. Und Ausnahme müssen jeweils behandelt werden. Hier ist, wie ich es getestet:

@Test
public void testThrowsExceptionWhenWrongSku() {

    // Given
    String articleSimpleSku = "999-999";
    int amountOfTransactions = 1;
    Exception exception = null;

    // When
    try {
        createNInboundTransactionsForSku(amountOfTransactions, articleSimpleSku);
    } catch (RuntimeException e) {
        exception = e;
    }

    // Then
    shouldValidateThrowsExceptionWithMessage(exception, MESSAGE_NON_EXISTENT_SKU);
}

private void shouldValidateThrowsExceptionWithMessage(final Exception e, final String message) {
    assertNotNull(e);
    assertTrue(e.getMessage().contains(message));
}

Nur eine Matcher machen, die ausgeschaltet und dies, wie schaltet werden können:

public class ExceptionMatcher extends BaseMatcher<Throwable> {
    private boolean active = true;
    private Class<? extends Throwable> throwable;

    public ExceptionMatcher(Class<? extends Throwable> throwable) {
        this.throwable = throwable;
    }

    public void on() {
        this.active = true;
    }

    public void off() {
        this.active = false;
    }

    @Override
    public boolean matches(Object object) {
        return active && throwable.isAssignableFrom(object.getClass());
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("not the covered exception type");
    }
}

Um es zu verwenden:

hinzufügen public ExpectedException exception = ExpectedException.none();, dann:

ExceptionMatcher exMatch = new ExceptionMatcher(MyException.class);
exception.expect(exMatch);
someObject.somethingThatThrowsMyException();
exMatch.off();

In JUnit 4 oder höher können Sie die Ausnahmen wie folgt testen

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


dies eine Menge von Funktionen zur Verfügung, die verwendet werden kann, unsere JUnit-Tests zu verbessern.
Wenn Sie siehe Beispiel unten Ich teste 3 Dinge, auf die Ausnahme.

  1. Die Art der Ausnahme ausgelöst
  2. Die Ausnahmemeldung
  3. Die Ursache für die Ausnahme


public class MyTest {

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

    ClassUnderTest classUnderTest;

    @Before
    public void setUp() throws Exception {
        classUnderTest = new ClassUnderTest();
    }

    @Test
    public void testAppleisSweetAndRed() throws Exception {

        exceptions.expect(Exception.class);
        exceptions.expectMessage("this is the exception message");
        exceptions.expectCause(Matchers.<Throwable>equalTo(exceptionCause));

        classUnderTest.methodUnderTest("param1", "param2");
    }

}

Wir können eine Assertion verwenden nach dem Verfahren scheitern, die eine Ausnahme zurückgeben muss:

try{
   methodThatThrowMyException();
   Assert.fail("MyException is not thrown !");
} catch (final Exception exception) {
   // Verify if the thrown exception is instance of MyException, otherwise throws an assert failure
   assertTrue(exception instanceof MyException, "An exception other than MyException is thrown !");
   // In case of verifying the error message
   MyException myException = (MyException) exception;
   assertEquals("EXPECTED ERROR MESSAGE", myException.getMessage());
}

Zusätzlich zu dem, was NamShubWriter gesagt hat, stellen Sie sicher, dass:

  • Das ExpectedException Beispiel ist Öffentlichkeit ( Verwandte Frage )
  • Die ExpectedException nicht instanziiert in etwa dem @Before Verfahren. Diese Post deutlich erklärt alle Feinheiten von JUnit Reihenfolge der Ausführung.

Do nicht Sie folgendermaßen vor:

@Rule    
public ExpectedException expectedException;

@Before
public void setup()
{
    expectedException = ExpectedException.none();
}

Schließlich this Blog-Post deutlich zeigt, wie zu behaupten, dass eine gewisse Ausnahme ausgelöst wird.

Ich empfehle Bibliothek assertj-core Ausnahme in JUnit-Test zu behandeln

In Java 8, wie folgt aus:

//given

//when
Throwable throwable = catchThrowable(() -> anyService.anyMethod(object));

//then
AnyException anyException = (AnyException) throwable;
assertThat(anyException.getMessage()).isEqualTo("........");
assertThat(exception.getCode()).isEqualTo(".......);

junit4 Lösung mit Java8 ist diese Funktion zu nutzen:

public Throwable assertThrows(Class<? extends Throwable> expectedException, java.util.concurrent.Callable<?> funky) {
    try {
        funky.call();
    } catch (Throwable e) {
        if (expectedException.isInstance(e)) {
            return e;
        }
        throw new AssertionError(
                String.format("Expected [%s] to be thrown, but was [%s]", expectedException, e));
    }
    throw new AssertionError(
            String.format("Expected [%s] to be thrown, but nothing was thrown.", expectedException));
}

Die Verwendung ist dann:

    assertThrows(ValidationException.class,
            () -> finalObject.checkSomething(null));

Beachten Sie, dass die einzige Einschränkung besteht darin, einen final Objektverweis in Lambda-Ausdruck zu verwenden. Diese Lösung erlaubt es Test Behauptungen weiterhin statt erwarten thowable bei Methode Ebene @Test(expected = IndexOutOfBoundsException.class) Lösung.

Nehmen Sie zum Beispiel, Sie wollen für unten genannte Codefragment Junit schreiben

public int divideByZeroDemo(int a,int b){

    return a/b;
}

public void exceptionWithMessage(String [] arr){

    throw new ArrayIndexOutOfBoundsException("Array is out of bound");
}

Der obige Code ist für eine unbekannte Ausnahme zu testen, und die unter einem auftreten kann, sind eine Ausnahme mit benutzerdefinierter Nachricht geltend zu machen.

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

private Demo demo;
@Before
public void setup(){

    demo=new Demo();
}
@Test(expected=ArithmeticException.class)
public void testIfItThrowsAnyException() {

    demo.divideByZeroDemo(5, 0);

}

@Test
public void testExceptionWithMessage(){


    exception.expectMessage("Array is out of bound");
    exception.expect(ArrayIndexOutOfBoundsException.class);
    demo.exceptionWithMessage(new String[]{"This","is","a","demo"});
}

Mit Java 8 Sie eine Methode erstellen können einen Code nehmen zu überprüfen und erwartete Ausnahme als Parameter:

private void expectException(Runnable r, Class<?> clazz) { 
    try {
      r.run();
      fail("Expected: " + clazz.getSimpleName() + " but not thrown");
    } catch (Exception e) {
      if (!clazz.isInstance(e)) fail("Expected: " + clazz.getSimpleName() + " but " + e.getClass().getSimpleName() + " found", e);
    }
  }

und dann in Ihrem Test:

expectException(() -> list.sublist(0, 2).get(2), IndexOutOfBoundsException.class);

Vorteile:

  • nicht auf jeder Bibliothek unter Berufung
  • lokalisierte Check - präziser und ermöglicht es, mehrere Behauptungen wie diese in einem Test zu haben, wenn nötig
  • einfach zu bedienen

Meine Lösung mit Java 8 lambdas:

public static <T extends Throwable> T assertThrows(Class<T> expected, ThrowingRunnable action) throws Throwable {
    try {
        action.run();
        Assert.fail("Did not throw expected " + expected.getSimpleName());
        return null; // never actually
    } catch (Throwable actual) {
        if (!expected.isAssignableFrom(actual.getClass())) { // runtime '!(actual instanceof expected)'
            System.err.println("Threw " + actual.getClass().getSimpleName() 
                               + ", which is not a subtype of expected " 
                               + expected.getSimpleName());
            throw actual; // throw the unexpected Throwable for maximum transparency
        } else {
            return (T) actual; // return the expected Throwable for further examination
        }
    }
}

Sie haben einen FunctionalInterface zu definieren, weil Runnable nicht den erforderlichen throws nicht erklären.

@FunctionalInterface
public interface ThrowingRunnable {
    void run() throws Throwable;
}

Das Verfahren kann wie folgt verwendet werden:

class CustomException extends Exception {
    public final String message;
    public CustomException(final String message) { this.message = message;}
}
CustomException e = assertThrows(CustomException.class, () -> {
    throw new CustomException("Lorem Ipsum");
});
assertEquals("Lorem Ipsum", e.message);

Es gibt zwei Arten des Schreibens Testfall

  1. Beschriften Sie den Test mit der Ausnahme, die durch das Verfahren ausgelöst. So etwas wie dieses @Test(expected = IndexOutOfBoundsException.class)
  2. Sie können einfach die Ausnahme in der Testklasse fangen den Try-Catch-Block verwenden und auf der Nachricht geltend machen, die aus dem Verfahren in Testklasse geworfen wird.

    try{
    }
    catch(exception to be thrown from method e)
    {
         assertEquals("message", e.getmessage());
    }
    

Ich hoffe, das beantwortet Ihre Frage Glückliches Lernen ...

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top