Comment puis-je utiliser JUnit4 idiomatiquement pour tester qu'un code lève une exception?
Bien que je puisse certainement faire quelque chose comme ça:
@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 un Assert.xyz ou quelque chose qui est beaucoup moins délicat et beaucoup plus dans l'esprit de JUnit pour ce genre de situations.
org.mockito.Mockito.verify
avec divers paramètres pour m'assurer que certaines choses se sont produites (telles qu'un service d'enregistrement a été appelé avec les paramètres corrects) avant que l'exception ne soit levée.Réponses:
Cela dépend de la version de JUnit et des bibliothèques d'assert que vous utilisez.
La réponse originale
JUnit <= 4.12
était:Bien que la réponse https://stackoverflow.com/a/31826781/2986984 ait plus d'options pour JUnit <= 4.12.
Référence :
la source
ArrayList
répondeget()
n'est pas pertinent. Si je choisissais à l'avenir de passer à un tableau primitif, je devrais alors changer cette implémentation de test. La structure des données doit être masquée, afin que le test puisse se concentrer sur le comportement de la classe .Edit: Maintenant que JUnit 5 et JUnit 4.13 sont sortis, la meilleure option serait d'utiliser
Assertions.assertThrows()
(pour JUnit 5) etAssert.assertThrows()
(pour JUnit 4.13). Voir mon autre réponse pour plus de détails.Si vous n'avez pas migré vers JUnit 5, mais pouvez utiliser JUnit 4.7, vous pouvez utiliser la
ExpectedException
règle:C'est bien mieux que
@Test(expected=IndexOutOfBoundsException.class)
parce que le test échouera s'ilIndexOutOfBoundsException
est lancé avantfoo.doStuff()
Voir cet article pour plus de détails
la source
ExpectedException
classe a des moyens de faire correspondre le message de l'exception, ou même d'écrire votre propre correspondance qui dépend de la classe de l'exception. Deuxièmement, vous pouvez définir votre attente immédiatement avant la ligne de code que vous prévoyez de lever l'exception - ce qui signifie que votre test échouera si la mauvaise ligne de code lève l'exception; alors qu'il n'y a aucun moyen de le faire avec la solution de skaffman.Soyez prudent en utilisant l'exception attendue, car elle affirme uniquement que la méthode a levé cette exception, pas une ligne de code particulière dans le test.
J'ai tendance à l'utiliser pour tester la validation des paramètres, car ces méthodes sont généralement très simples, mais les tests plus complexes pourraient être mieux servis avec:
Faites preuve de jugement.
la source
ExpectedException
, la chose normale à faire est de définir l'attente immédiatement avant la ligne à laquelle vous prévoyez de lever l'exception. De cette façon, si une ligne antérieure lève l'exception, elle ne déclenchera pas la règle et le test échouera.Comme indiqué précédemment, il existe de nombreuses façons de gérer les exceptions dans JUnit. Mais avec Java 8, il y en a un autre: utiliser les expressions Lambda. Avec les expressions Lambda, nous pouvons obtenir une syntaxe comme celle-ci:
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 acceptant cette interface attendra et sera prêt à gérer une exception.
Il s'agit d'une technique relativement simple mais puissante.
Jetez un œil à cet article 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.
la source
new DummyService()::someMethod
unMethodHandle
, mais cette approche fonctionne aussi bien avec les expressions lambda.dans junit, il existe quatre façons de tester l'exception.
junit5.x
pour junit5.x, vous pouvez utiliser
assertThrows
comme suitjunit4.x
pour junit4.x, utilisez l'attribut facultatif «attendu» de Test annonation
pour junit4.x, utilisez la règle ExpectedException
vous pouvez également utiliser la méthode classique try / catch largement utilisée dans le cadre de junit 3
donc
pour plus d'informations, vous pouvez lire ce document et le guide de l'utilisateur junit5 pour plus de détails.
la source
Trowable
à la méthodeExpectedException.expect
. veuillez voir sa signature . @miusertl; dr
post-JDK8: utilisez AssertJ ou lambdas personnalisés pour affirmer un comportement exceptionnel .
pré-JDK8: Je vais recommander le bon vieux
try
-catch
bloc. ( N'oubliez pas d'ajouter unefail()
assertion avant lecatch
bloc )Indépendamment de Junit 4 ou JUnit 5.
la longue histoire
Il est possible de vous écrire vous -même
try
-catch
bloquer ou utiliser les outils JUnit (@Test(expected = ...)
ou la@Rule ExpectedException
fonction de règle JUnit).Mais ces moyens ne sont pas si élégant et ne se mélangent pas bien sage lisibilité avec d' autres outils. De plus, l'outillage JUnit présente certains pièges.
Le bloc
try
-catch
vous devez écrire le bloc autour du comportement testé et écrire l'assertion dans le bloc catch, cela peut être correct, mais beaucoup trouvent que ce style interrompt le flux de lecture d'un test. De plus, vous devez écrire unAssert.fail
à la fin dutry
bloc. Sinon, le test peut manquer un côté des assertions; PMD , findbugs ou Sonar détecteront ces problèmes.La
@Test(expected = ...)
fonctionnalité est intéressante car vous pouvez écrire moins de code, puis écrire ce test est censé être moins sujet aux erreurs de codage. Mais cette approche fait défaut dans certains domaines.De plus, comme l'attente est placée dans la méthode, selon la façon dont le code testé est écrit, la mauvaise partie du code de test peut lever l'exception, conduisant à un test faussement positif et je ne suis pas sûr que PMD , findbugs ou Sonar donnera des conseils sur ce code.
La
ExpectedException
règle est également une tentative de corriger les mises en garde précédentes, mais cela semble un peu gênant à utiliser car il utilise un style d'attente, les utilisateurs d' EasyMock connaissent très bien ce style. Cela peut être pratique pour certains, mais si vous suivez les principes de développement conduit par le comportement (BDD) ou d' Arrange Act Assert (AAA), laExpectedException
règle ne rentrera pas dans ces styles d'écriture. En dehors de cela, il peut souffrir du même problème que le@Test
chemin, selon l'endroit où vous placez l'attente.Même l'exception attendue est placée avant l'instruction de test, elle rompt votre flux de lecture si les tests suivent BDD ou AAA.
Voir également ce numéro de commentaire sur JUnit de l'auteur de
ExpectedException
. JUnit 4.13-beta-2 déconseille même ce mécanisme:Ces options ci-dessus ont donc toute leur charge de mises en garde et ne sont clairement pas à l'abri des erreurs de codeur.
Il y a un projet dont j'ai pris connaissance après avoir créé cette réponse qui semble prometteur, c'est une exception de capture .
Comme le dit la description du projet, il a permis à un codeur d'écrire dans une ligne de code fluide interceptant l'exception et de proposer cette exception pour la dernière assertion. Et vous pouvez utiliser n'importe quelle bibliothèque d'assertions comme Hamcrest ou AssertJ .
Un exemple rapide tiré de la page d'accueil:
Comme vous pouvez voir que le code est vraiment simple, vous interceptez l'exception sur une ligne spécifique, l'
then
API est un alias qui utilisera les API AssertJ (similaire à l'utilisationassertThat(ex).hasNoCause()...
). À un moment donné, le projet s'est appuyé sur FEST-Assert, l'ancêtre d'AssertJ . EDIT: Il semble que le projet prépare un support Lambdas Java 8.Actuellement, cette bibliothèque présente deux lacunes:
Au moment d'écrire ces lignes, il est à noter que cette bibliothèque est basée sur Mockito 1.x car elle crée une maquette 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 s'il était basé sur Mockito 2 dans la version actuelle, cela nécessiterait de déclarer un fabricant de maquette global (
inline-mock-maker
), ce qui peut ne pas être ce que vous voulez, car ce fabricant de maquette a différents inconvénients que le fabricant de maquette classique.Cela nécessite encore une autre dépendance de test.
Ces problèmes ne s'appliqueront pas une fois que la bibliothèque prend en charge les lambdas. Cependant, la fonctionnalité sera dupliquée par le jeu d'outils AssertJ.
Tenant compte de tout si vous ne voulez pas utiliser l'outil catch-exception, je recommanderai l'ancienne bonne façon du bloc
try
-catch
, du moins jusqu'au JDK7. Et pour les utilisateurs de JDK 8, vous préférerez peut-être utiliser AssertJ car il offre plus que la simple affirmation d'exceptions.Avec le JDK8, les lambdas entrent en scène de test, et ils se sont révélés être un moyen intéressant d'affirmer un comportement exceptionnel. AssertJ a été mis à jour pour fournir une belle API fluide pour affirmer un comportement exceptionnel.
Et un exemple de test avec AssertJ :
Avec une réécriture presque complète de JUnit 5, les assertions ont été un peu améliorées , elles peuvent s'avérer intéressantes comme une méthode prête à l'emploi pour affirmer correctement une exception. Mais vraiment l'API d'assertion est encore un peu pauvre, il n'y a rien à l'extérieur
assertThrows
.Comme vous l'avez remarqué,
assertEquals
revient toujoursvoid
, et en tant que tel ne permet pas de chaîner des assertions comme AssertJ.Aussi, si vous vous souvenez d'un conflit de noms avec
Matcher
ouAssert
, soyez prêt à rencontrer le même conflit avecAssertions
.Je voudrais conclure qu'aujourd'hui (2017-03-03) la facilité d'utilisation d' AssertJ , l'API découvrable, le rythme rapide de développement et en tant que dépendance de facto aux tests est la meilleure solution avec JDK8 quel que soit le cadre de test (JUnit ou non), les JDK antérieurs devraient plutôt compter sur
try
-catch
blocs même s'ils se sentent maladroits.Cette réponse a été copiée d' une autre question qui n'a pas la même visibilité, je suis le même auteur.
la source
Maintenant que JUnit 5 et JUnit 4.13 sont sortis, la meilleure option serait d'utiliser
Assertions.assertThrows()
(pour JUnit 5) etAssert.assertThrows()
(pour JUnit 4.13). Voir le Guide de l'utilisateur de Junit 5 .Voici un exemple qui vérifie qu'une exception est levée et utilise la vérité pour faire des assertions sur le message d'exception:
Les avantages par rapport aux approches des autres réponses sont:
throws
clauseUne méthode similaire sera ajoutée à
org.junit Assert
JUnit 4.13.la source
Que diriez-vous de cela: attrapez une exception très générale, assurez-vous qu'elle sort du bloc catch, puis affirmez que la classe de l'exception est ce que vous attendez d'elle. Cette affirmation échouera si a) l'exception est du mauvais type (par exemple, si vous avez obtenu un pointeur nul à la place) et b) l'exception n'a jamais été levée.
la source
assertEquals(ExpectedException.class, e.getClass())
vous montrera les valeurs attendues et réelles lorsque le test échoue.Solution de style BDD : JUnit 4 + Catch Exception + AssertJ
Dépendances
la source
Utilisation d'une assertion AssertJ , qui peut être utilisée avec JUnit:
C'est mieux que
@Test(expected=IndexOutOfBoundsException.class)
parce qu'il garantit que la ligne attendue dans le test a levé l'exception et vous permet de vérifier plus de détails sur l'exception, comme le message, plus facilement:Instructions Maven / Gradle ici.
la source
assertThat
, toujours celle AssertJ. De plus, la méthode JUnit renvoie uniquement un type "normal", tandis que la méthode AssertJ renvoie uneAbstractAssert
sous-classe ... permettant la chaîne de méthodes comme ci-dessus (ou quels que soient les termes techniques pour cela ...).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 assistant, vous écririez
Ceci est moins détaillé que la règle ExpectedException 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 ça aide.
la source
foo
estfinal
elle échouera parce que vous ne pouvez pas proxyfoo
?Mise à jour: JUnit5 a une amélioration des exceptions d' essai:
assertThrows
.l'exemple suivant provient de: Junit 5 User Guide
Réponse originale en utilisant JUnit 4.
Il existe plusieurs façons de tester qu'une exception est levée. J'ai également discuté des options ci-dessous dans mon article Comment écrire d'excellents tests unitaires avec JUnit
Définissez le
expected
paramètre@Test(expected = FileNotFoundException.class)
.En utilisant
try
catch
Test avec
ExpectedException
règle.Vous pouvez en savoir plus sur les tests d'exceptions dans le wiki JUnit4 pour les tests d'exceptions et bad.robot - Expecting Exceptions JUnit Rule .
la source
Vous pouvez également le faire:
la source
Assert.fail()
, nonassert
, juste au cas où vos tests s'exécuteraient dans un environnement où les assertions ne sont pas activées.À mon humble avis, la meilleure façon de vérifier les exceptions dans JUnit est le modèle try / catch / fail / assert:
Cela
assertTrue
pourrait être un peu fort pour certaines personnes, donc celaassertThat(e.getMessage(), containsString("the message");
pourrait être préférable.la source
Solution JUnit 5
Plus d'infos sur JUnit 5 sur http://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions
la source
expectThrows()
est une partie TestNG, pas une JUnitLa réponse la plus flexible et élégante pour Junit 4 que j'ai trouvée sur le blog Mkyong . Il a la flexibilité d'
try/catch
utiliser l'@Rule
annotation. J'aime cette approche car vous pouvez lire les attributs spécifiques d'une exception personnalisée.la source
J'ai essayé de nombreuses méthodes ici, mais elles étaient soit compliquées, soit ne répondaient pas tout à fait à mes exigences. En fait, on peut tout simplement écrire une méthode d'aide:
Utilisez-le comme ceci:
Zéro dépendances: pas besoin de mockito, pas besoin de powermock; et fonctionne très bien avec les classes finales.
la source
Solution Java 8
Si vous souhaitez une solution qui:
Voici une fonction utilitaire que j'ai écrite:
( extrait de mon blog )
Utilisez-le comme suit:
la source
JUnit a un support intégré pour cela, avec un attribut "attendu"
la source
Dans mon cas, je reçois toujours RuntimeException de db, mais les messages diffèrent. Et l'exception doit être gérée respectivement. Voici comment je l'ai testé:
la source
} catch (
, vous devez insérerfail("no exception thrown");
Créez simplement un Matcher qui peut être activé et désactivé, comme ceci:
Pour l'utiliser:
ajoutez
public ExpectedException exception = ExpectedException.none();
, puis:la source
Dans JUnit 4 ou version ultérieure, vous pouvez tester les exceptions comme suit
cela fournit de nombreuses 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.
la source
Nous pouvons utiliser un échec d'assertion après la méthode qui doit retourner une exception:
la source
catch
avalera la trace de la pile si une autre exception est levée, perdant des informations utilesEn plus de ce que NamShubWriter a dit, assurez-vous que:
Ne faites pas ceci:
Enfin, ce billet de blog illustre clairement comment affirmer qu'une certaine exception est levée.
la source
Je recommande la bibliothèque
assertj-core
pour gérer l'exception dans le test junitEn java 8, comme ceci:
la source
La solution Junit4 avec Java8 consiste à utiliser cette fonction:
L'utilisation est alors:
Notez que la seule limitation est d'utiliser une
final
référence d'objet dans l'expression lambda. Cette solution permet de poursuivre les assertions de test au lieu de s'attendre à ce qu'elles puissent être testées au niveau de la méthode en utilisant la@Test(expected = IndexOutOfBoundsException.class)
solution.la source
Prenez par exemple, vous voulez écrire Junit pour le fragment de code mentionné ci-dessous
Le code ci-dessus consiste à tester une exception inconnue qui peut se produire et celui ci-dessous consiste à affirmer une exception avec un message personnalisé.
la source
Voici une autre façon de vérifier la méthode levée ou non.
la source
Le framework JUnit a une
assertThrows()
méthode:org.junit.jupiter.api.Assertions
classe;org.junit.Assert
classe;org.junit.jupiter:junit-jupiter-api
à votre projet et vous obtiendrez une version parfaitement fonctionnelle de JUnit 5.la source
Avec Java 8, vous pouvez créer une méthode prenant un code à vérifier et l'exception attendue comme paramètres:
puis à l'intérieur de votre test:
Avantages:
la source