La méthode suivante ne doit être appelée que s'il a été vérifié qu'il y a des chiffres invalides (en appelant une autre méthode). Comment puis-je tester le throw
-line dans l'extrait de code suivant? Je sais que l'one-way pourrait être de fusionner ensemble le VerifyThereAreInvalidiDigits
et cette méthode. Je cherche d'autres idées. Je voudrais également ne pas écrire un test unitaire qui exerce un code qui ne devrait jamais être exécuté.Comment tester un code qui ne devrait jamais être exécuté?
Répondre
Si le « jeter » la déclaration en question est vraiment injoignable dans tout scénario possible, alors il devrait être supprimé et remplacé par:
Debug.Fail("This should be unreachable; please find and fix the bug that caused this to be reached.");
Si le code est accessible alors écrire un test d'unité teste ce scénario. Les scénarios de rapport d'erreurs pour les méthodes accessibles au public sont des scénarios parfaitement valides. Vous devez gérer toutes les entrées correctement, même les mauvaises entrées. Si la bonne chose à faire est de lancer une exception, alors testez que vous lancez une exception. MISE À JOUR: selon les commentaires, il est en fait impossible de toucher l'erreur et donc le code est inaccessible. Mais maintenant le Debug.Fail n'est pas accessible non plus, et il ne compile pas parce que le compilateur note qu'une méthode qui retourne une valeur a un point d'extrémité atteignable.
Le premier problème ne devrait pas réellement être un problème; L'outil de couverture de code doit sûrement être configurable pour ignorer le code de débogage inaccessible. Mais à la fois problème peut être résolu par la réécriture de la boucle:
public int FirstInvalidDigitPosition
{
get
{
int index = 0;
while(true)
{
Debug.Assert(index < this.positions.Length, "Attempt to get invalid digit position but there are no invalid digits!");
if (!this.positions[index].Valid) return index;
index++;
}
}
}
Une autre approche serait de réorganiser le code de sorte que vous n'avez pas le problème en premier lieu:
public int? FirstInvalidDigitPosition {
get {
for (int index = 0; index < this.positions.Count; ++index) {
if (!this.positions[index].Valid) return index;
}
return null;
}
}
et maintenant vous n'avez pas besoin de restreindre les appelants pour appeler AreThereInvalidDigits en premier; Il est juste légal d'appeler cette méthode à tout moment. Cela semble être la chose la plus sûre à faire. Les méthodes qui explosent lorsque vous ne faites pas de vérification coûteuse pour vérifier qu'elles sont sûres d'appeler sont des méthodes fragiles et dangereuses.
J'aurais dû le mentionner, je fais du TDD, ce qui m'empêche de tester des cas fictifs: P C'est une méthode de classe publique, mais interne à un module. Donc, lancer une exception ne fait pas partie de l'exigence, donc pas de test. –
Aussi Debug.Fail ne sera toujours pas couvert par le code, en remplaçant également ce lancer avec Debug.Fail est une erreur de compilation. –
@ user93422: J'ai mis à jour ma réponse pour répondre à vos questions. –
Je ne comprends pas pourquoi vous ne voudriez pas écrire un test unitaire qui utilise un "code qui ne devrait pas arriver".
Si cela "ne devrait pas arriver", alors pourquoi écrivez-vous le code? Parce que vous pensez que cela pourrait arriver bien sûr - peut-être qu'une erreur dans un futur refactoring va casser votre autre validation et que ce code sera exécuté.
Si vous pensez que cela vaut la peine d'écrire le code, il vaut la peine de le tester.
Je suis d'accord - écrire un code qui «ne devrait jamais être exécuté» me semble être un exercice plutôt inutile. – EnOpenUK
bon point. J'écris ce code parce que C# requiert une méthode non void pour finir soit avec return ou throw. Je préférerais préférer l'exception de lancement au moment de l'exécution. Donc je n'ai pas besoin d'écrire cette ligne moche. Ce qui signifie que j'ai besoin d'une solution de contournement pour la fonctionnalité de langue, ou trouver une faille dans la conception. –
Pour améliorer la conception, j'utiliserais une méthode plutôt qu'une propriété. Une propriété "ressemble" à une simple variable membre accès à l'appelant, donc ils sont susceptibles d'être * surpris * si cela prend beaucoup de temps à exécuter, a des effets secondaires (comme changer les variables membres dans un appel 'get'), provoque événements à déclencher ou déclenche une exception. D'un autre côté, il est normal qu'une méthode renvoie une valeur pour indiquer "non trouvé" (par exemple -1, comme string.IndexOf) ou une exception - une méthode est donc un meilleur choix de conception. –
Une partie de l'objectif de l'essai est de tester les deux choses qui devrait arriver et les choses qui peuvent arriver.
Si vous avez du code qui devrait jamais exécuter, mais pourrait dans les bonnes conditions (ou mal), vous pouvez vérifier que l'exception se produit dans les bonnes conditions (dans Unit Test Framework de MS) en décorant votre test méthode avec:
[ExpectedException(typeof(InvalidOperationException))]
Je fais du TDD, en tant que tel, je ne teste pas les choses qui peuvent _can_ mais jamais _should_ arriver. Dans ce cas, cette exception est une indication d'un bogue dans le code, et PAS une condition exceptionnelle. –
Il est parfois nécessaire d'écrire des petits morceaux de code qui ne peut pas exécuter, juste pour apaiser un compilateur (par exemple, si une fonction qui jettent toujours une exception, quitte l'application, etc. est appelé à partir une fonction qui est supposée renvoyer une valeur, le compilateur peut insister pour que l'appelant inclue un "return 0", "Return Nothing" ", etc. déclaration qui ne peut jamais être exécutée. Je ne pense pas que l'on devrait être obligé de tester un tel "code", car il peut être impossible de le faire exécuter sans sérieusement casser d'autres parties du système.
Une question plus intéressante vient avec le code que le processeur ne devrait jamais être capable d'exécuter dans des circonstances normales, mais qui existe pour minimiser les dommages causés par des circonstances anormales. Par exemple, certaines applications critiques pour la sécurité que j'ai début écrit avec quelque chose comme code (application réelle est le code de la machine, étant donné ci-dessous est pseudo-code)
register = 0 test register for zero if non-zero goto dead register = register - 1 test register for zero if non-zero goto okay1 dead: shut everything down goto dead okay1: register = register + 1 if non-zero goto dead
Je ne sais pas exactement comment on pourrait s'y prendre pour les tests ce code dans le cas d'échec. Le but du code est de s'assurer que si le registre a subi des dommages électrostatiques ou autres, ou qu'il ne fonctionne pas, le système s'arrêtera en toute sécurité. En l'absence de matériel très sophistiqué, je ne sais pas comment tester un tel code.
- 1. La session ne devrait jamais expirer par elle-même
- 2. Ce qui devrait être dans un contrôleur de navigation
- 3. NullReferenceException sur le code qui devrait fonctionner
- 4. Pourquoi un bloc T-SQL donne-t-il une erreur même s'il ne devrait même pas être exécuté?
- 5. ne peut pas sembler effectuer ce qui devrait être un tweak de navigation simple
- 6. avertissements qui ne sont jamais loin
- 7. Comment créer une colonne qui ne peut jamais être mise à jour?
- 8. Installer un fichier qui doit être supprimé uniquement lors d'une désinstallation réelle et jamais écrasé
- 9. Installez le programme qui doit être exécuté en tant qu'administrateur
- 10. Quelle sous-classe de Throwable devrait être attrapée et laquelle ne devrait pas l'être?
- 11. Quelle devrait être la raison derrière cette ligne qui fuit?
- 12. quel code devrait être pour l'application de comète côté serveur
- 13. faire un formulaire qui ne peut pas être fermé
- 14. Le lieur ne trouve pas de classe qui devrait être disponible
- 15. JUnit 4.x: pourquoi @Before n'est jamais exécuté?
- 16. Comment cela devrait-il être conçu?
- 17. QGraphicsRectItem :: boundingRect() retourne un QRectF qui est 1px plus grand que ce qu'il devrait être
- 18. À quel point mon code Ajax devrait-il être sophistiqué?
- 19. Ce qui devrait être dans deux jours Formation Hibernate
- 20. ajaxForm (options) ce qui devrait être passé aux options?
- 21. Ne devrait pas être ces avertissements avec g ++ -Wall?
- 22. Caractéristiques d'une structure d'application ASP.NET/code ne doit jamais manquer
- 23. problème nextSibling, devrait être simple
- 24. marge/Rembourrage où il ne devrait pas être
- 25. Shoulda on Rails - devrait être rendu différé
- 26. C#, C++/cli: Comment tester un composant qui ne peut être chargé qu'une seule fois par processus?
- 27. Comment trouver le code non-exécuté
- 28. Comment écrire (tester) du code qui ne sera pas optimisé par le compilateur/JIT?
- 29. Unity + Caching: comment conserver une instance d'objet qui devrait être un singletone
- 30. codes dans onClickListener ne peut pas être exécuté
Le simple fait que vous le dites ne devrait pas être exécuté et ne peut pas être atteint me dit "Retirez-le". Vous avez validé la chaîne comme étant invalide pour arriver ici, donc vous savez que la propriété va retourner quelque chose. – Michael