8 branches pour essayer avec des ressources - jacoco couverture possible?
J'ai un code qui utilise essayer avec des ressources et dans jacoco il arrive que seulement la moitié couvert. Toutes les lignes de code source sont au vert, mais j'ai un peu de jaune symbole me disant que seulement 4 des 8 branches sont couvertes.
Je vais avoir du mal à déterminer ce que toutes les branches sont, et comment écrire du code qui les couvre. Trois endroits possibles jeter PipelineException
. Ce sont createStageList()
, processItem()
et l'implicite close()
- De ne pas jeter de toutes les exceptions,
- lancer une exception de
createStageList()
- lancer une exception de
processItem()
- lancer une exception de
close()
- lancer une exception de
processItem()
etclose()
Je ne peux pas penser à un autre cas, mais je n'ai encore que 4 de 8 couverts.
Quelqu'un peut m'expliquer pourquoi il est 4 de 8 et est de toute façon il a frappé tous les 8 branches? Je ne suis pas habile avec les decyrpting/lecture/interprétation de byte code, mais peut-être que vous êtes... 🙂 j'ai déjà vu https://github.com/jacoco/jacoco/issues/82, mais ni lui, ni le problème c'références aider beaucoup (autres que notant que cela est dû à généré par le compilateur, blocs)
Hmm, juste que j'ai fini d'écrire cela, j'ai eu une pensée sur ce cas(s) peut ne pas être pas été testés par ce que je mentionne ci-dessus... je vais poster une réponse si j'ai bien compris. Je suis sûr que cette question et la réponse sera aider quelqu'un en tout cas.
EDIT: Nope, je n'ai pas à le trouver. Jeter RuntimeExceptions (non traités par le bloc catch) ne couvre pas toutes les branches plus
- Pouvez-vous poster le classfile s'il vous plaît?
- Non, je ne peux pas poster mon client code.
- La meilleure couverture que j'ai réussi à atteindre avec Eclemma (Emma dans Eclipse) est "3 de 8 branches raté", mais Cobertura dans Jenkins alors encore ne montre que 4/8. Espérons que, bientôt, ces outils de couverture va gérer essayer-avec-les ressources correctement.
- Notez que de nombreuses constructions qui JaCoCo ne peut pas couvrir entièrement, comme ceux-ci, sont destinés à vous aider à réduire le nombre de chemins possibles dans le code (et donc de faire des erreurs). En visant une couverture de 100% sur celles-ci est le plus souvent impossible, aussi il ne sera pas ajouter beaucoup à votre test de qualité (mais il coûte beaucoup d'effort).
Vous devez vous connecter pour publier un commentaire.
Eh bien, je ne peux pas vous dire quel est le problème exact avec Jacoco est, mais je peux vous montrer comment Essayer Avec des Ressources est compilé. Fondamentalement, il ya beaucoup de compilateur a généré des commutateurs pour gérer les exceptions levées à différents points.
Si nous prenons le code suivant et de le compiler
Et puis démonter, nous obtenons
Pour ceux qui ne parlent pas de pseudo-code binaire, c'est à peu près équivalent à celui-ci pseudo Java. J'ai eu à utiliser gotos parce que le bytecode n'a pas vraiment d'correspondent à Java de flux de contrôle.
Comme vous pouvez le voir, il ya beaucoup de cas à gérer les diverses possibilités de la suppression d'exceptions. Il n'est pas raisonnable pour être en mesure de couvrir tous ces cas. En fait, la
goto L59
branche sur le premier bloc try est impossible à atteindre, depuis la première prise Throwable va attraper toutes les exceptions.javac
question spécifique, par exemple l'Éclipse du compilateur ne produisent pas inaccessible bytecode.Je peux couvrir tous les 8 branches, donc ma réponse est OUI. Regardez le code suivant, ce n'est qu'un rapide essai, mais ça marche (ou voir mon github: https://github.com/bachoreczm/basicjava et le "trywithresources' package, vous pourrez y trouver, comment essayez-avec-ressources, reportez-vous à 'ExplanationOfTryWithResources' classe):
Pas de véritable question, mais je voulais jeter plus de recherche là-bas. tl;dr = On dirait que vous pouvez atteindre 100% de couverture pour essayer-et enfin, mais pas pour essayer-avec-ressource.
Naturellement, il y a une différence entre la vieille école essayez-enfin, et Java7 try-with-resources. Voici deux équivalent exemples montrant la même chose en utilisant d'autres approches.
Old School exemple (un try-finally approche):
Java7 exemple (un try-with-ressource):
Analyse: de la vieille école, par exemple:
À l'aide de Jacoco 0.7.4.201502262128 et JDK 1.8.0_45, j'ai été en mesure d'obtenir 100% de la ligne, de l'enseignement et de la direction générale de la couverture sur le Old School exemple à l'aide de la suite de 4 tests:
Jacoco indique 2 branches à l'intérieur de l'essayer (sur la valeur null est à vérifier) et 4 à l'intérieur de l', enfin, sur la valeur null est à vérifier). Tous sont entièrement couvertes.
Analyse: java-7 exemple:
Si les mêmes 4 tests contre la Java7 style exemple, jacoco indique 6/8 branches sont couvertes (à essayer lui-même) et 2/2 sur le null-vérifier à l'intérieur de l'essayer. J'ai essayé un certain nombre de tests supplémentaires afin d'augmenter la couverture, mais je ne trouve pas de moyen de faire mieux que 6/8. Comme d'autres l'ont indiqué, le code décompilé (que je n'ai regarder aussi) pour le java-7 exemple suggère que le compilateur java est de générer inaccessible segments pour essayer-avec-ressource. Jacoco déclaration (avec raison) que ces segments existent.
Mise à jour: à l'Aide de Java7 style de codage, vous pourriez être en mesure d'obtenir une couverture de 100% SI à l'aide d'un Java7 JRE (voir Matyas réponse ci-dessous). Cependant, l'utilisation de Java7 style de codage avec un Java8 JRE, je crois que vous touchez la 6/8 branches couvertes. Même code, juste différent JRE. Semble que le code d'octets est créé de manière différente entre les deux Jre avec le Java8 une création inaccessible voies.
try-with-resources
a 3 la gestion des exceptions régions, un départ avantconn.createStatement()
, l'un autour du corps et une autre juste autour de l'appel àif(stmt != null){ stmt.close(); }
. En outre, il ya un appel àThrowable.addSuppressed()
etif
pour se prémunir contre la suppression de la même l'exception.Quatre ans, mais quand même...
AutoCloseable
AutoCloseable
try
bloc maisAutoCloseable
est nullCi-dessus répertorie tous les 7 conditions de la raison pour les 8 branches est due à plusieurs reprises, fait état.
Toutes les branches peut être atteint, la
try-with-resources
est assez simple compilateur de sucre (au moins par rapport àswitch-on-string
) - si elles ne peuvent pas être atteint, il est, par définition, un bug du compilateur.Seulement 6 les tests unitaires sont réellement nécessaires (dans l'exemple de code ci-dessous,
throwsOnClose
est@Ingore
d et de la direction générale de la couverture est 8/8.Également noter que Throwable.addSuppressed(Throwable) ne peut pas supprimer lui-même, de sorte que le bytecode généré contient un supplément de garde (IF_ACMPEQ - référence de l'égalité) pour éviter cela). Heureusement, cette branche est couvert par la remise à l'écriture, jetez-sur-fermer et de le jeter à l'écriture-et-fermer les cas, comme le pseudo-code binaire variable fentes sont réutilisés par l'extérieur 2 de 3 gestionnaire d'exception régions.
C'est pas un problème avec Jacoco - en fait, l'exemple de code dans la question n ° 82 est incorrect, car il n'y a pas dupliqué null vérifie et il n'y a aucun bloc catch imbriqué environnant les fermer.
De test JUnit démonstration de 8 de 8 branches couvertes
Mise en garde
Mais pas dans l'OP du code de l'échantillon, il existe un cas qui ne peuvent pas être testés autant que je sache.
Si vous passez la référence de la ressource comme un argument, puis en Java 7/8 vous devez avoir une variable locale à affecter à:
Dans ce cas, le code généré sera toujours en gardant la référence à la ressource. Le syntatic sucre est mise à jour en Java 9, où la variable locale n'est plus nécessaire:
try(arg){ /*...*/}
Supplémentaire Suggèrent d'utiliser la bibliothèque pour éviter les branches entièrement
Certes, certains de ces branches peuvent être radiés comme irréalistes, c'est à dire où le bloc try utilise le
AutoCloseable
sans nul de vérification ou d'où la référence de la ressource (with
) ne peut pas être null.Souvent votre application ne prend pas de soins où il a échoué à ouvrir le fichier, le modifier ou de le fermer - la granularité de l'échec n'est pas pertinent (sauf si l'application est en particulier les fichiers, par exemple, l'explorateur de fichier ou traitement de texte).
En outre, dans le cas des OP de code, afin de tester la valeur null fermer le chemin d'accès que vous auriez à refactoriser le bloc try dans une méthode protégée, la sous-classe et de fournir un NOOP mise en œuvre, tout cela à obtenir une couverture sur les branches qui ne sera jamais pris à l'état sauvage.
J'ai écrit un petit Java 8 bibliothèque io.earcam.rien d'exceptionnel (en Maven Central) qui traite de la plupart vérifié exception standard.
Pertinentes à la question: il fournit une bande de zéro-branche, one-liners pour
AutoCloseable
s, la conversion checked exceptions à décochée.Exemple: Port Libre Finder
Jacoco a récemment résolu ce problème, Version 0.8.0 (2018/01/02)
"Lors de la création de différents rapports générés par le compilateur artefacts sont filtrés, qui exigent inutile et parfois impossible astuces pour ne pas avoir partielle ou l'oubli de couverture:
http://www.jacoco.org/jacoco/trunk/doc/changes.html
j'ai eu un problème similaire avec quelque chose comme ceci:
il se plaint que 2 des 8 branches n'étaient pas couverts. fini par faire ceci:
pas d'autres modifications, et j'ai maintenant atteint 100%....