Comment affirmer qu'une certaine exception est jetée dans les tests de JUnit 4?

Comment puis-je utiliser L'idiome JUnit4 pour tester qu'un code jette une exception?

alors que je peux certainement faire quelque chose comme ceci:

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

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

  assertTrue(thrown);
}

je me souviens qu'il y a une annotation ou une Assertion.xyz ou quelque chose qui est beaucoup moins encombrants et bien plus dans l'esprit de JUnit pour ces sortes de situations.

1672
demandé sur rgettman 2008-10-01 10:56:08

30 réponses

JUnit 4 a le soutien pour ceci:

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

référence: https://junit.org/junit4/faq.html#atests_7

1996
répondu skaffman 2018-04-18 05:27:06

Edit maintenant que JUnit5 est sorti, la meilleure option serait d'utiliser Assertions.assertThrows() (voir mon autre réponse ).

si vous n'avez pas migré vers JUnit 5, mais pouvez utiliser JUnit 4.7, vous pouvez utiliser la ExpectedException règle:

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

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

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

c'est beaucoup mieux que @Test(expected=IndexOutOfBoundsException.class) parce que l'essai échouera si IndexOutOfBoundsException est lancé avant foo.doStuff()

voir cet article pour plus de détails

1183
répondu NamshubWriter 2017-10-01 16:43:56

soit prudent en utilisant l'exception attendue, parce qu'il affirme seulement que la méthode jeté cette exception, pas une ligne particulière de code dans l'essai.

j'ai tendance à l'utiliser pour tester la validation des paramètres, parce que ces méthodes sont généralement très simples, mais des tests plus complexes pourraient être mieux servis avec:

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

appliquer le jugement.

417
répondu daveb 2008-10-01 09:36:52

comme on l'a déjà dit, il y a plusieurs façons de traiter les exceptions dans JUnit. Mais avec Java 8 Il y en a un autre: utiliser des Expressions Lambda. Avec les Expressions Lambda, nous pouvons obtenir une syntaxe comme celle-ci:

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

assertThrown accepte une interface fonctionnelle, dont les instances peuvent être créées avec des expressions lambda, des références de méthode ou des références de constructeur. assertThrown accepter que l'interface attendra et être prêt à gérer une exception.

c'est une technique relativement simple mais puissante.

Regardez ce billet de blog décrivant cette technique: http://blog.codeleak.pl/2014/07/junit-testing-exception-with-java-8-and-lambda-expressions.html

le code source peut être trouvé ici: https://github.com/kolorobot/unit-testing-demo/tree/master/src/test/java/com/github/kolorobot/exceptions/java8

Divulgation: je suis l'auteur du blog et du projet.

190
répondu Rafal Borowiec 2016-11-27 15:07:00

dans junit, il y a quatre façons de tester exception.

  • pour junit4.x, utiliser l'attribut facultatif "prévu" de l'annonation d'essai

    @Test(expected = IndexOutOfBoundsException.class)
    public void testFooThrowsIndexOutOfBoundsException() {
        foo.doStuff();
    }
    
  • pour junit4.x, utilisez la règle D'exception prévue

    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();
        }
    }
    
  • vous pouvez également utiliser la méthode classique try / catch largement utilisé sous junit 3 framework

    @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.
        }
    }
    
  • enfin, pour junit5.x, vous pouvez également utiliser assertThrows comme suit

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

    • la 1ère méthode est utilisée lorsque vous ne voulez tester le type d'exception
    • les trois autres façons sont utilisées lorsque vous voulez plus de message d'exception de test
    • si vous utilisez junit 3, alors le 3ème est préféré
    • si vous aimez junit 5, alors vous devriez aimer le 4ème
  • pour plus d'informations, vous pouvez lire ce document et guide de l'utilisateur junit5 pour plus de détails.

87
répondu walsh 2018-06-08 13:53:58

tl; dr

  • pre-JDK8 : je recommanderai l'ancien bloc try - catch .

  • post-JDK8: utiliser AssertJ ou custom lambdas pour affirmer comportement" exceptionnel .

indépendamment de Junit 4 ou JUnit 5.

la longue histoire

il est possible de vous écrire un faites-le vous-même try - catch bloquez ou utilisez les outils JUnit ( @Test(expected = ...) ou la fonctionnalité @Rule ExpectedException de la règle JUnit).

mais cette façon ne sont pas si élégant et ne se mélangent pas bien lisibilité Sage avec d'autres outils.

  1. Le try - catch bloc, vous devez écrire le bloc autour de l'essai de comportement, et d'écrire l'affirmation dans le bloc catch, qui peut être bien, mais beaucoup trouvent que ce style interrompt la lecture d'un test. Vous devez également écrire un Assert.fail à la fin du bloc try sinon le test peut manquer un côté des assertions; PMD , findbugs ou Sonar permettra de repérer ces problèmes.

  2. la fonctionnalité @Test(expected = ...) est intéressante car vous pouvez écrire moins de code et ensuite écrire ce test est censé être moins sujet à des erreurs de codage. mais cette approche manque dans certains domaines.

    • si le test doit vérifier des choses supplémentaires sur l'exception comme la cause ou le message (les bons messages d'exception sont vraiment importants, avoir un type d'exception précis peut ne pas être suffisant).
    • aussi comme l'attente est placée autour dans la méthode, en fonction de la façon dont le code testé est écrit, puis la mauvaise partie du code test peut jeter l'exception, conduisant à un test faussement positif et je ne suis pas sûr que PMD , findbugs ou Sonar donnera des conseils sur un tel code.

      @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. la règle ExpectedException est également une tentative de corriger les mises en garde précédentes, mais il se sent un peu mal à l'aise à utiliser comme il utilise un style attente, EasyMock les utilisateurs connaissent très bien ce style. Il pourrait être commode pour certains, mais si vous suivez développement axé sur le comportement (BDD) ou arranger acte affirmer (AAA) principes la règle ExpectedException ne conviendra pas dans ce style d'écriture. En dehors de cela, il peut souffrir de la même question que la voie @Test , selon l'endroit où vous placez l'attente.

    @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
    }
    

    même l'exception attendue est placée avant l'énoncé du test, il casse votre lecture du flux si les tests suivent BDD ou AAA.

    voir Aussi cette commentaire question sur JUnit de l'auteur de ExpectedException .

ainsi ces options ci-dessus ont toute leur charge de mises en garde, et clairement pas à l'abri des erreurs de codage.

  1. il y a un projet que j'ai pris conscience après avoir créé cette réponse qui semble prometteuse, c'est catch-exception .

    comme le dit la description du projet, il a permis à un codeur d'écrire dans une ligne fluide de code attraper l'exception et offrir cette exception pour une assertion ultérieure. Et vous pouvez utiliser n'importe quelle bibliothèque d'assertion comme Hamcrest ou AssertJ .

    un exemple rapide tiré de la page d'accueil:

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

    comme vous pouvez le voir le code est vraiment simple, vous attrapez l'exception sur une ligne spécifique, L'API then est un alias qui utilisera AssertJ APIs (similaire à l'utilisation de assertThat(ex).hasNoCause()... ). à un moment donné, le projet s'est appuyé sur FEST-affirmer l'ancêtre de AssertJ . EDIT: il semble que le le projet brasse un support Java 8 Lambdas.

    actuellement, cette bibliothèque présente deux lacunes :

    • Au moment de la rédaction de ce document, il convient de dire que cette bibliothèque est fondée sur Mockito 1.x car elle crée un simulacre de l'objet testé derrière la scène. Comme Mockito n'est toujours pas mis à jour cette bibliothèque ne peut pas fonctionner avec les classes finales ou les méthodes finales . Et même si elle était basée sur mockito 2 dans le version actuelle, cela nécessiterait de déclarer un mockmaker mondial ( inline-mock-maker ), quelque chose qui ne peut pas ce que vous voulez, car ce mockmaker a différents inconvénients que le mockmaker régulier.

    • il nécessite encore une autre dépendance de test.

    ces problèmes ne s'appliqueront pas une fois que la bibliothèque supportera lambdas, mais la fonctionnalité sera dupliquée par assertj toolset.

    en tenant compte de tous si vous ne voulez pas utiliser l'outil catch-exception, je recommanderai l'ancienne bonne voie du bloc try - catch , au moins jusqu'à la JDK7. Et pour les utilisateurs de JDK 8 vous pourriez préférer utiliser AssertJ car il offre peut-être plus que simplement affirmer des exceptions.

  2. avec le JDK8, lambdas entrent dans la scène d'essai, et ils se sont avérés être une manière intéressante d'affirmer exceptionnelle comportement. AssertJ a été mis à jour pour fournir une API agréable fluent pour affirmer un comportement exceptionnel.

    et un essai sur échantillon avec 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. avec une réécriture presque complète de JUnit 5, assertions ont été améliorée un peu, ils peuvent se révéler intéressant comme une façon hors de la boîte d'affirmer correctement l'exception. Mais en réalité L'API d'assertion est encore un peu pauvre, il n'y a rien dehors. assertThrows .

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

    Comme vous l'avez remarqué, assertEquals est encore de retour void , et en tant que tel ne permet pas de chaînage des affirmations comme AssertJ.

    aussi si vous vous souvenez du nom clash avec Matcher ou Assert , soyez prêt à rencontrer le même clash avec Assertions .

je voudrais conclure qu'aujourd'hui (2017-03-03) AssertJ 's facilité d'utilisation, API détectable, rythme rapide de développement et comme un de facto dépendance de test est la meilleure solution avec JDK8 quel que soit le cadre de test (JUnit ou non), jdks avant devrait plutôt compter sur try - catch même s'ils se sentent grognons.

cette réponse a été copiée de une autre question qui n'ont pas la même visibilité, je suis du même auteur.

62
répondu Brice 2018-07-05 08:51:46

Comment à ce sujet: prendre un très exception générale, assurez-vous qu'il sort du bloc catch, affirment alors que la classe de l'exception est ce que vous attendez qu'elle soit. Cette affirmation échouera si a) l'exception est du mauvais type (p. ex. si vous avez un pointeur Null à la place) et b) l'exception n'a jamais été lancée.

public void testFooThrowsIndexOutOfBoundsException() {
  Throwable e = null;

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

  assertTrue(e instanceof IndexOutOfBoundsException);
}
32
répondu Johan 2014-11-13 00:22:07

BDD Style Solution: JUnit 4 + Catch Exception + AssertJ

@Test
public void testFooThrowsIndexOutOfBoundsException() {

    when(foo).doStuff();

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

}

code Source

dépendances

eu.codearte.catch-exception:catch-exception:1.3.3
30
répondu MariuszS 2015-01-08 19:35:25

utilisant une AssertJ assertion, qui peut être utilisé à côté de JUnit:

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

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

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

c'est mieux que @Test(expected=IndexOutOfBoundsException.class) parce qu'il garantit la ligne attendue dans le test jeté l'exception et vous permet de vérifier plus de détails sur l'exception, tels que le message, plus facile:

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

instructions Maven/Gradle ici.

30
répondu weston 2016-10-11 18:24:43

maintenant que JUnit 5 est sorti, la meilleure option est d'utiliser Assertions.assertThrows() (voir le Junit 5 Guide de l'Utilisateur ).

voici un exemple qui vérifie qu'une exception est lancée, et utilise Truth pour faire des affirmations sur le message d'exception:

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

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

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

Les avantages sur les approches dans les autres réponses sont:

  1. Construit en JUnit
  2. vous obtenez un message d'exception utile si le code dans la lambda ne jette pas une exception, et un stacktrace si elle jette une exception différente
  3. Concis
  4. permet à vos tests de suivre Arrange-Act-Assert
  5. vous pouvez indiquer précisément quel code vous vous attendez à jeter l'exception
  6. vous n'avez pas besoin d'énumérer l'exception prévue dans la throws clause
  7. Vous pouvez utiliser l'affirmation cadre de votre choix pour faire des assertions sur l'exception interceptée

une méthode similaire sera ajoutée à org.junit Assert en Juin 4.13.

30
répondu NamshubWriter 2017-10-01 17:17:00

pour résoudre le même problème j'ai mis en place un petit projet: http://code.google.com/p/catch-exception /

en utilisant ce petit helper vous écririez

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

c'est moins verbeux que la règle D'exception prévue de JUnit 4.7. Par rapport à la solution fournie par skaffman, vous pouvez spécifier dans quelle ligne de code vous attendez l'exception. J'espère que cette aide.

29
répondu rwitzel 2011-10-28 09:26:21

mise à Jour: JUnit5 a une amélioration pour les exceptions de test: assertThrows .

l'exemple suivant est tiré de: Junit 5 User Guide

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

réponse Originale à cette question en utilisant JUnit 4.

Il y a plusieurs façons de tester qu'une exception est levée. J'ai également discuté des options ci-dessous dans mon post Comment écrire grand essais unitaires avec JUnit

définit le expected paramètre @Test(expected = FileNotFoundException.class) .

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

utilisant 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 avec ExpectedException la Règle.

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

vous pouvez en savoir plus sur le test des exceptions dans JUnit4 wiki pour le test des exceptions et bad.robot - Attend Exceptions JUnit Règle .

24
répondu Dilini Rajapaksha 2018-01-05 16:03:12

vous pouvez aussi faire ceci:

@Test
public void testFooThrowsIndexOutOfBoundsException() {
    try {
        foo.doStuff();
        assert false;
    } catch (IndexOutOfBoundsException e) {
        assert true;
    }
}
19
répondu John Mikic 2014-11-13 00:21:01

à mon humble avis, la meilleure façon de vérifier l'existence d'exceptions dans JUnit est le try/catch/échec/assert motif:

// 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()); 
}

le assertTrue pourrait être un peu fort pour certaines personnes, donc assertThat(e.getMessage(), containsString("the message"); pourrait être préférable.

12
répondu Alex Collins 2017-03-14 18:07:21

JUnit 5 Solution

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

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

plus d'informations à propos de JUnit 5 sur http://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions

10
répondu Daniel Käfer 2016-07-24 15:00:31

j'ai essayé beaucoup de méthodes ici, mais elles étaient compliquées ou ne répondaient pas tout à fait à mes exigences. En fait, on peut écrire une méthode helper tout simplement:

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;
    }
}

utilisez - le comme ceci:

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

Zéro dépendances: pas besoin de mockito, pas besoin powermock; et fonctionne très bien avec final classes.

9
répondu Hugh Perkins 2012-10-10 15:02:44

JUnit a intégré un support pour cela, avec un " attribut prévu

8
répondu Mark Bessey 2008-10-01 07:05:49

Java 8 solution

si vous souhaitez une solution qui:

  • utilise Java 8 lambdas
  • Ne pas dépend d'aucun JUnit magie
  • vous permet de vérifier plusieurs exceptions à l'intérieur d'une même méthode d'essai
  • vérifie qu'une exception est lancée par un ensemble spécifique de lignes dans votre méthode d'essai au lieu d'une ligne inconnue dans la méthode d'essai complète
  • donne l'objet d'exception réelle qui a été lancé afin que vous puissiez l'examiner plus en détail

Voici une fonction d'utilité que j'ai écrit:

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.
}

( tiré de mon blog )

utilisez - le comme suit:

@Test
public void testThrows()
{
    RuntimeException e = expectException( RuntimeException.class, () -> 
        {
            throw new RuntimeException( "fail!" );
        } );
    assert e.getMessage().equals( "fail!" );
}
8
répondu Mike Nakis 2018-02-11 16:38:50

dans mon cas, je reçois toujours RuntimeException de db, mais les messages diffèrent. Et les exceptions doivent être traitées respectivement. Voici comment je l'ai testé:

@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));
}
6
répondu Macchiatow 2013-07-02 09:03:57

en juin 4 ou plus tard, vous pouvez tester les exceptions comme suit

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



cela fournit beaucoup de fonctionnalités qui peuvent être utilisées pour améliorer nos tests JUnit.

si vous voyez l'exemple ci-dessous, je teste 3 choses sur l'exception.

  1. Le Type de l'exception levée
  2. le Message d'exception
  3. la cause de l'exception



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

}
5
répondu Jobin Joseph 2016-12-08 05:48:19

nous pouvons utiliser une assertion échoue après la méthode qui doit retourner une exception:

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());
}
5
répondu Shessuky 2017-12-20 10:34:05

la réponse la plus souple et élégante pour Junit 4 j'ai trouvé dans le Mkyoung blog . Il a la flexibilité du try/catch en utilisant le @Rule annotation. J'ai aimé cette approche parce que j'ai déjà besoin de lire les attributs spécifiques d'une exception personnalisée.

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

    }

}
5
répondu Dherik 2018-08-06 13:17:09

en plus de ce que NamShubWriter a dit, assurez-vous que:

  • l'instance D'exception prévue est publique ( question connexe )
  • La ExpectedException n'est pas instancié à-dire, la méthode @before. Ce post explique clairement toutes les subtilités de L'ordre D'exécution de JUnit.

Faire pas faites ceci:

@Rule    
public ExpectedException expectedException;

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

enfin, ce billet de blog illustre clairement comment affirmer qu'une certaine exception est lancée.

4
répondu Bruce Wayne 2017-05-23 12:18:24

faites juste une allumette qui peut être éteinte et allumée, comme ceci:

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

pour l'utiliser:

ajouter public ExpectedException exception = ExpectedException.none(); , puis:

ExceptionMatcher exMatch = new ExceptionMatcher(MyException.class);
exception.expect(exMatch);
someObject.somethingThatThrowsMyException();
exMatch.off();
4
répondu Tor P 2016-03-02 02:28:41

par exemple, vous voulez écrire Junit pour le fragment de code ci-dessous mentionné

public int divideByZeroDemo(int a,int b){

    return a/b;
}

public void exceptionWithMessage(String [] arr){

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

le code ci-dessus est de tester pour une exception inconnue qui peut se produire et le suivant est d'affirmer une certaine exception avec le message personnalisé.

 @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"});
}
1
répondu Shirsh Sinha 2016-10-29 07:34:18

avec Java 8 Vous pouvez créer une méthode prenant un code à vérifier et l'exception attendue comme paramètres:

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);
    }
  }

et ensuite dans votre test:

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

prestations:

  • ne s'appuyant sur aucune bibliothèque
  • contrôle localisé - plus précis et permet d'avoir plusieurs assertions comme celle-ci dans un seul test si nécessaire
  • facile à utiliser
0
répondu fahrenx 2017-10-01 12:03:38

ma solution en utilisant 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
        }
    }
}

vous devez définir une Interfacefonctionnelle, parce que Runnable ne déclare pas le throws requis .

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

La méthode peut être utilisée comme suit:

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);
0
répondu heio 2017-10-04 12:03:26

Il y a deux façons d'écrire des cas de test

  1. Annoter l'essai à l'exception de ce qui est jeté par la méthode. Quelque chose comme ce @Test(expected = IndexOutOfBoundsException.class)
  2. vous pouvez simplement attraper l'exception dans la classe test en utilisant le bloc try catch et affirmer sur le message qui est lancé de la méthode dans la classe test.

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

j'espère que cela répond à votre question Heureux apprentissage...

0
répondu Mohit ladia 2017-11-09 07:23:04

Junit4 solution avec Java8 est pour utiliser cette fonction:

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));
}

L'Usage est alors:

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

notez que la seule limitation est d'utiliser une référence d'objet final dans l'expression lambda. Cette solution permet de continuer les assertions de test au lieu de s'attendre à ce que le thowable au niveau de la méthode en utilisant @Test(expected = IndexOutOfBoundsException.class) solution.

0
répondu Donatello 2018-04-06 16:32:25

je vous conseille de la bibliothèque assertj-core pour gérer exception dans junit test

en java 8, comme ceci:

//given

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

//then
AnyException anyException = (AnyException) throwable;
assertThat(anyException.getMessage()).isEqualTo("........");
assertThat(exception.getCode()).isEqualTo(".......);
0
répondu Piotr R 2018-07-18 11:32:37