Comment tester qu'aucune exception n'est levée?
Je sais que la seule façon de le faire serait:
@Test
public void foo(){
try{
//execute code that you expect not to throw Exceptions.
}
catch(Exception e){
fail("Should not have thrown any exception");
}
}
Est-il le moyen le plus propre de le faire. (Probablement en utilisant Junit est @Rule
?)
- Un test Unitaire est jugé avoir échoué si elle lève une exception autre que prévue exception. Habituellement, aucune exception n'est prévue.
- N'est-il pas une distinction entre l'échec et l'erreur dans JUnit? La première signifie que le test a échoué, le second signifie quelque chose d'inattendu s'est produit.
- double possible de Comment puis-je tester si une exception est levée pas?
Vous devez vous connecter pour publier un commentaire.
Vous vous approchez de cette façon le mal. Il suffit de tester votre fonctionnalité: si une exception est levée, le test échouera automatiquement. Si aucune exception n'est levée, vos tests va jusqu'vert.
J'ai remarqué que cette question suscite l'intérêt, de temps en temps, donc je vais développer un peu.
Arrière-plan de tests unitaires
Quand vous êtes les tests unitaires, il est important de définir pour vous-même ce que vous considérez comme une unité de travail. En gros: une extraction de votre base de code qui peut ou peut ne pas inclure plusieurs méthodes ou classes qui représente un seul morceau de fonctionnalité.
Ou, comme défini dans L'art de Tests Unitaires, 2e Édition par Roy Osherove, page 11:
Ce qui est important à comprendre, c'est que l'on unité de travail habituellement n'est pas seulement une méthode, mais à la base c'est une méthode, et après qu'il est encapsulé par une autre unité de l'œuvre.
Idéalement, vous devriez avoir une méthode de test pour chaque unité de travail de sorte que vous pouvez toujours consulter immédiatement lorsque les choses vont mal. Dans cet exemple, il existe une méthode de base appelé
getUserById()
qui vous permettra de revenir à un utilisateur et il y a un total de 3 unités d'œuvres.La première unité de travail doit tester si oui ou non un utilisateur valide est retourné dans le cas d'entrée valides et invalides.
Toutes les exceptions qui sont levées par la source de données doivent être traitées ici: si aucun utilisateur n'est présent, il devrait y avoir un test qui démontre qu'une exception est levée lorsque l'utilisateur ne peut pas être trouvé. Un exemple de cela pourrait être le
IllegalArgumentException
qui est pris avec le@Test(expected = IllegalArgumentException.class)
annotation.Une fois que vous avez traité tous vos usecases pour cette unité de base de travail, vous montez d'un niveau. Ici vous faire exactement la même chose, mais vous ne gérer les exceptions qui viennent à partir du niveau juste en dessous de l'actuel. Cela permet à vos tests de code bien structuré et permet d'exécuter rapidement grâce à l'architecture de trouver l'endroit où les choses vont mal, au lieu d'avoir à sauter dans tous les sens.
La manipulation d'un des tests de validité et la mauvaise entrée
À ce stade, il devrait être clair de la façon dont nous allons gérer ces exceptions. Il y a 2 types d'entrée: valide d'entrée et de défectueux entrée (l'entrée est valable dans le sens le plus strict, mais il n'est pas correct).
Lorsque vous travaillez avec des valide entrée de la configuration de l'implicite de l'espérance que quelque soit le test que vous écrivez, fonctionne.
Tel un appel de méthode peut ressembler à ceci:
existingUserById_ShouldReturn_UserObject
. Si cette méthode échoue (par exemple: une exception est levée), alors vous savez que quelque chose s'est mal passé et vous pouvez commencer à creuser.Par l'ajout d'un autre test (
nonExistingUserById_ShouldThrow_IllegalArgumentException
) qui utilise le défectueux d'entrée et s'attend à une exception près, vous pouvez voir si votre méthode est ce qu'il est censé faire l'erreur de saisie.TL;DR
Que vous étiez en train de faire deux choses dans votre test: vérifier la validité et la mauvaise entrée. En scindant en deux méthode que chacun de faire une chose, vous aurez beaucoup plus claire des tests et une bien meilleure vue d'ensemble de l'endroit où les choses vont mal.
En gardant les couches de l'unité des œuvres à l'esprit que vous pouvez également réduire le nombre de tests que vous besoin d'une couche est plus élevé dans la hiérarchie, parce que vous n'avez pas de compte pour chaque chose qui pourrait mal tourner dans les basses couches: les couches au-dessous de l'actuel sont une quasi-garantie de vos dépendances et si quelque chose va mal, il est dans votre calque courant (en supposant que les couches inférieures ne jetez pas les erreurs elles-mêmes).
expected
annotation. Si vous voulez tester un scénario où votre code ne fonctionne pas et que vous voulez voir si l'erreur est correctement géré: utilisationexpected
et peut-être utiliser affirme pour déterminer si elle a été résolu.expected
et de vérifier si l'exception s'est produite. @ThorbjørnRavnAndersen: Certainement, je ne suis pas certain que. Mais comme ce que j'ai vu de sa description du problème, il n'y a pas de raison de le faire ici (et il est en contradiction avec son titre).expected
et appeler la méthode avec des données erronées. Si les deux tour vert vous devez supposer que l'enregistrement fonctionne aussi bien (plus de journalisation des cadres ont leurs propres tests). Si vous effectuez la gestion des erreurs autres que l'abattage, alors vous pourriez envisager d'ajouter affirme pour vérifier si cela a été résolu correctement. Vous ne devriez pas explicitement vérifier si votre catch-bloc a été appelé: la mise en œuvre, pas de fonctionnalité.throws IllegalArgumentException
à votre test. Ce que vous voulez à la fin, c'est que votre test s'allume en rouge si il y a une exception. Eh bien, devinez quoi? Vous n'avez pas besoin d'écrirefail()
. Comme @Jeroen Vannevel a écrit: "si une exception est levée, le test échouera automatiquement."Je suis tombé sur ce en raison de SonarQube, la règle de "squid:S2699": "Ajouter au moins une affirmation de ce cas de test."
J'ai eu un test simple dont le seul objectif était de passer sans lever des exceptions.
Considérer ce simple code:
Ce genre d'affirmation peut être ajouté à tester cette méthode?
Bien sûr, vous pouvez faire un try-catch autour d'elle, mais c'est seulement le code de la météorisation.
La solution vient de JUnit lui-même.
Dans le cas où aucune exception n'est levée et que vous souhaitez explicitement illustrer ce comportement, il suffit d'ajouter
expected
comme dans l'exemple suivant:Test.None.class
est la valeur par défaut pour la valeur attendue.testng
Java 8 qui rend ce beaucoup plus facile, et Kotlin/Scala doublement.
On peut écrire un petit utilitaire de la classe
et puis votre code devient simplement:
Si vous n'avez pas d'accès à Java 8, je voudrais utiliser une douloureusement old java installation: aribitrary des blocs de code et un simple commentaire
Et enfin, avec kotlin, une langue que je suis récemment tombé en amour avec:
Si il y a beaucoup de place pour jouer avec exactement comment vous souhaitez exprimer cela, j'ai toujours été un fan de couramment affirmations.
Concernant
C'est correct, en principe, mais incorrecte dans la conclusion.
Java permet des exceptions pour les flux de contrôle. Ceci est fait par le JRE runtime lui-même dans l'Api comme
Double.parseDouble
via unNumberFormatException
etPaths.get
via unInvalidPathException
.Donné que vous avez écrit un composant qui permet de valider le Nombre de chaînes de
Double.ParseDouble
, peut-être à l'aide d'une Regex, peut-être écrite à la main de l'analyseur, ou peut-être quelque chose qui incorpore certaines autres règles de domaine qui limite la portée d'un double à quelque chose de spécifique, la meilleure façon de tester ce composant? Je pense qu'un évident test consisterait à affirmer que, lorsque la chaîne est analysée, aucune exception n'est levée. Je voudrais écrire ce test en utilisant soit le au-dessus deassertDoesNotThrow
ou/*comment*/{code}
bloc. Quelque chose commeJe voudrais aussi vous encourager à paramétrer ce test sur
input
à l'aide deThéories
ouParamétrée
de sorte que vous pouvez plus facilement ré-utiliser ce test pour les autres entrées. Alternativement, si vous souhaitez aller plus exotique, vous pouvez aller faire un test de l'outil de production (et cette). TestNG a un meilleur support pour les tests paramétrés.Ce que je trouve particulièrement désagréable est la recommandation de l'utilisation de
@Test(expectedException=IllegalArgumentException.class)
, cette exception est dangereusement large. Si votre code des changements tels que le composant sous test, le constructeur aif(constructorArgument <= 0) throw IllegalArgumentException()
, et votre test a été la fourniture de 0 pour cet argument parce que c'était pratique-et cela est très fréquent, en raison de la bonne génération de données de test est étonnamment un problème difficile--, puis votre test sera vert-bar même si il teste rien. Un tel test est pire qu'inutile.Assert.assertThrows
pour vérifier que le code renvoie une exception.Si vous avez la malchance d'attraper toutes les erreurs dans votre code.
Vous pouvez bêtement faire
Exception ex
devrait être= null;
avant de pouvoir le tester.Avec AssertJ couramment affirmations 3.7.0:
JUnit 5 (Jupiter) fournit trois fonctions à l'exception de contrôle d'absence/présence:
●
assertAll()
Affirme que tous fourni
executables
ne jetez pas des exceptions.
●
assertDoesNotThrow()
Affirme que l'exécution de l'
fourni
executable
/supplier
ne pas jeter tout type de exception.
Cette fonction est disponible
depuis JUnit 5.2.0 (29 avril 2018).
●
assertThrows()
Affirme que l'exécution de la fourniture
executable
jette une exception de la
expectedType
et renvoie la exception.
Exemple
JUnit5 ajoute le assertAll() méthode pour cet objectif précis.
source: JUnit 5 de l'API
Vous pouvez le faire en utilisant un @à la Règle et ensuite appeler la méthode reportMissingExceptionWithMessage comme indiqué ci-dessous:
C'est la Scala, mais il peut facilement être fait de la même manière en Java.
Si vous voulez tester que si votre cible de test consomme de l'exception. Il suffit de laisser le test (simulation d'un collaborateur à l'aide de jMock2):
Le test ne serait pass si votre cible ne consomment de l'exception levée, sinon le test échoue.
Si vous voulez tester votre exception de la consommation de la logique, les choses deviennent plus complexes. Je suggère de déléguer la consommation à un collaborateur qui pourrait se moque de lui. Par conséquent, le test pourrait être:
Mais parfois, il est plus conçu si vous voulez juste de l'enregistrer. Dans ce cas, cet article(http://java.dzone.com/articles/monitoring-declarative-transac, http://blog.novoj.net/2008/09/20/testing-aspect-pointcuts-is-there-an-easy-way/) peuvent vous aider si vous insistez tdd dans ce cas.
Utilisation assertNull(...)
assertNull
n'est jamais exécuté soit. Cependant, la rapide lecteur a l'impression que l'affirmation est faite que vraiment vérifie la non-jeter des cas. En d'autres termes: si le bloc catch est atteint, l'exception est toujours non-null - il peut donc être remplacée par un simplefail
.assertNull(e)
fera rapport, le test a échoué, comme l'a déclarée
ne peut pas êtrenull
dans lecatch
bloc ... Mike c'est juste bizarre de programmation :-/ ... oui au moins utiliserfail()
comme Andreas ditVous pouvez vous attendre que l'exception n'est pas générée par la création d'une règle.
Cela peut ne pas être le meilleur moyen, mais il a certainement fait en sorte que l'exception n'est pas jeté par le bloc de code qui est en train d'être testé.
Vous pouvez créer n'importe quel type de vos propres affirmations basées sur des assertions de junit:
Et de test:
En général il y a la possibilité instantanément fail("bla bla bla") le test dans tous les scénarios, dans un endroit où il fait sens. Par exemple l'utiliser dans un bloc try/catch à l'échec si tout est jeté dans le cas du test:
C'est l'exemple de la méthode que nous avons test, supposons que nous avons une méthode qui ne doit pas échouer dans des circonstances particulières, mais il peut échouer:
La méthode ci-dessus est un exemple simple. Mais cela fonctionne pour les situations complexes, où l'échec n'est pas si évident.
Il y a les importations:
La suivante échoue le test pour toutes les exceptions, cocher ou décocher la case: