• 10 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 12/10/18

Arrêtez-vous sur la bonne exception

Servez-vous du panneau Test Explorer

Pour le scénario d'un test qui échoue à cause d'une exception inattendue, le panneau de Test Explorer est votre point de départ. Pour y accéder, allez dans le menu TEST | Windows | Test Explorer :

Menus pour aller dans le Test Explorer
Menus pour aller dans le Test Explorer

 Dans notre cas, sélectionnez le test VerifyAddTasks et démarrez-le avec un clic-droit Run Selected Tests :

Démarrez le test VerifyAddTasks
Démarrez le test VerifyAddTasks

La fenêtre de résultats du panneau Test Explorer de Visual Studio fournit un minimum d'informations pour vous aider à comprendre la cause de l’échec du test :

Echec de l'exécution d'un test unitaire
Échec de l'exécution d'un test unitaire

En premier, l’échec vient d’une exception levée par le code appelé (encadré rouge).

Ensuite, les détails de l’exception en question sont présentés (encadré vert) :

  • Son type (ici ArgumentNullException) ;

  • Et message Value cannot be null

Que vous donne cette information ? 

Le type de l’exception ainsi que le message indiquent qu’une méthode a sûrement reçu un paramètre avec une valeur nulle alors que ce n’était pas supporté. Il vous faut donc maintenant déterminer quelle est cette méthode qui lui passe null. Notez que le nom de ce paramètre est donné juste en dessous : source. Il correspond à l’énumération sur laquelle FirstOrDefault est appelée.

Vous pouvez trouver une partie de la réponse sous la section StackTrace : la pile des appels de méthode est affichée du dernier avant l’exception jusqu’au test unitaire (encadré bleu).

Paramétrez la gestion des exceptions

Reprenons notre investigation. Il est malheureusement trop tard pour faire quoi que ce soit. :o

En effet, il aurait fallu demander au débogueur d’arrêter l’exécution au moment et à l’endroit précis dans le code où l'exception est levée et non pas quand le test a échoué.

Pour cela, il suffit de passer par le menu DEBUG | Windows | Exception Settings :

Menu Exception Settings
Menu Exception Settings

Le panneau qui apparaît liste tous les types d’exceptions pouvant être levées :

Panneau de paramêtrage des exceptions
Panneau de paramétrage des exceptions

Nous ne sommes intéressés que par celles levées dans le cadre de .NET qui apparaissent sous la section Common Language Runtime Exceptions. Si l’on coche la case en face d’une exception (dans notre cas ArgumentNullException), le débogueur suspendra l’exécution, et l’instruction qui lève l’exception sera montrée dans l'éditeur.

Pour permettre ce comportement, cette fois-ci, le test est démarré à partir de la commande Debug (et non plus Run) : 

Déboguer un test unitaire
Déboguer un test unitaire

Cela signifie que le code va s'exécuter sous le contrôle du débogueur de Visual Studio.

Ainsi, le débogueur va s'arrêter sur la ligne de code levant l'exception. Dans notre cas, il s'arrête sur l’appel à la méthode FirstOrDefault :

Exécution en pause sur une exception
Exécution en pause sur une exception

La ligne en question est surlignée dans l’éditeur de code et un petit encart donne les détails de l'exception, comme son message.

Comme vous ne connaissez pas le code du test unitaire ni les méthodes qui y sont appelées, il est clairement très difficile de comprendre ce qui se passe et où en est l'exécution. Heureusement, le panneau Call Stack montrant la pile d'appels s'est automatiquement affiché lors de la détection de l'exception. Il permet de comprendre où nous en sommes de l'exécution à ce moment précis :

Panneau de la pile d'appels
Panneau de la pile d'appels

La méthode en haut de la pile indiquée avec la flèche incurvée, TodoModel.GetTask, est celle dans laquelle l'exception s'est produite. Elle est apparue automatiquement dans l’éditeur de code de Visual Studio.

La méthode suivante dans la pile, TodoModel.InternalAddTask, correspond à celle l'ayant appelée. On peut ainsi remonter dans le temps jusqu'à savoir à quel endroit du test nous en sommes. Pour cela, il suffit de descendre jusqu'à la méthode de T_TodoModel et de double-cliquer sur la ligne VerifyAddTasks (surlignée en bleu sur la copie d'écran précédente) :

Pile d'appels sur VerifyAddTasks
Pile d'appels sur VerifyAddTasks

La petite flèche incurvée apparaît à la fois dans la pile d'appels et dans le code de la méthode pour indiquer l'instruction correspondant à l'appel de la méthode TodoModel.CreateTask, c'est-à-dire la ligne au-dessus dans la pile d'appels :

Exécution au niveau de CreateTask
Exécution au niveau de CreateTask

Cette gymnastique permet de retrouver l’enchaînement des appels de méthodes ayant abouti à l’exception.

Si l’on se remet dans notre investigation, la collection _tasks sur laquelle est appelée FirstOrDefault semble ne pas être initialisée. Il serait intéressant de connaître la valeur de taskName pour laquelle l’exception a été levée. Il suffit pour cela de déplacer la souris dessus et sa valeur s’affichera directement dans l’éditeur, "sleep" dans notre cas :

Valeur de taskName
Valeur de taskName

Le dernier chapitre de ce cours reviendra en détail sur les différents moyens de visualiser et de modifier la valeur des paramètres et des champs des structures de données.

Résumé

Nous venons de voir comment demander au débogueur de s’arrêter dès qu’une exception est levée. Nous avons aussi visualisé l’enchaînement des exécutions de méthodes avec le panneau de la pile d’appels.

La question est maintenant de savoir comment demander au débogueur de s’arrêter, non pas au moment où l’exception est levée, mais plutôt à l’endroit du test unitaire qui va mener à l’erreur. On pourra alors retrouver l'état des variables locales de chaque méthode, ainsi que la valeur des différents paramètres utilisés lors des appels consécutifs.

La réponse se trouve dans le chapitre suivant. :)

Example of certificate of achievement
Example of certificate of achievement