Faites un arrêt sur image avant une exception
Est-ce que vous avez déjà regardé un film et pensé que vous aviez repéré un acteur faisant une apparition spéciale ? Les films ont généralement un rythme rapide, passant de scène en scène, alors il est difficile d’en être sûr. Quand cela arrive, votre cerveau pense : « Qu’est-ce qui vient d’interrompre mon immersion dans l’univers du film ? » Que faites-vous quand cela se produit ? Vous rembobinez probablement pour regarder la scène à nouveau. Vous effectuez peut-être un arrêt sur image pour examiner le détail. Parfois vous confirmez ce que vous avez vu, et parfois vous vous rendez compte que « non, ce n’est pas Elvis ! »
Votre code ressemble un peu à cela. Les instructions individuelles sont exécutées comme des images d’un film. Quand vous dézoomez sur le code, vous voyez différents niveaux d’abstraction. Plus vous vous éloignez, plus les instructions individuelles commencent à constituer des parties de méthodes, de classes, de paquets, et à la fin de l’application complète. Si un bug fait une apparition, il sera plus difficile de distinguer l’arbre de la forêt.
Lorsque vous recherchez un bug, vous avez besoin de voir les subtilités entre chaque déclaration de votre code, pour mieux comprendre ce qui échoue. Il vous faut vous concentrer sur les arbres individuels !
Attendez ! Notre code s’exécute à une telle vitesse, comment pourrions-nous suivre ce qu’il fait ?
C’est vrai. Les applications courent d’instruction en instruction. Pour suivre ce qu’il se passe, il est utile de se concentrer sur une partie spécifique du logiciel. Il vous faut donner un coup de frein et faire une pause lorsque la JVM voit une ligne de code intéressante. Vous pouvez alors la regarder se dérouler étape par étape !
Heureusement, les débuggers vous permettent d’arrêter le code n’importe où. Vous allez voir comment utiliser le débugger pour exécuter votre application jusqu’au moment juste avant qu’elle ne s’écroule. Ainsi, vous pouvez inspecter les preuves qui amènent à votre exception levée et commencer à formuler une théorie sur sa cause.
Lorsque nous avons exécuté le test qui échoue, vous avez vu une stack trace commençant par :
com.openclassrooms.debugging.exception.InvalidSaddleSizeException: Unexpected saddle size:-49.0
at com.openclassrooms.debugging.DragonSaddleSizeVerifier.verify(DragonSaddleSizeVerifier.java:13)
L’erreur montre que le code lève une exception Java personnalisée de typecom.openclassrooms.debugging.exception.InvalidSaddleSizeException
depuis la méthode verify()
de la classecom.openclassrooms.debugging.DragonSaddleSizeVerifier
. La stack trace donne également le numéro de ligne dans le fichier source. Regardons la ligne 13 :
package com.openclassrooms.debugging;
import com.openclassrooms.debugging.exception.InvalidSaddleSizeException;
public class DragonSaddleSizeVerifier {
public void verify(Double saddleSize) {
if (null == saddleSize) {
throw new InvalidSaddleSizeException("Unexpected saddle size of null");
}
if (saddleSize <= 0) {
throw new InvalidSaddleSizeException("Unexpected saddle size:" + saddleSize);
}
}
}
La ligne 13 prend la valeur de saddleSize passée à la ligne 7, et lève une exception en utilisant throw new validSaddleSizeException("Unexpected saddle size:" + saddleSize);
.
Installons un point d’arrêt à cette ligne et lançons le test à nouveau ! Un point d’arrêt est comme une pause dans le programme qui vous permet d’inspecter ce qu’il se passe, étape par étape. Pour en mettre un en place, trouvez la ligne de votre code sur laquelle vous voulez vous arrêter et cliquez sur la marge à côté. Elle devrait virer au rouge. Cela dira au débugger de lancer le programme et de faire une pause à cette ligne.
Vous pouvez maintenant exécuter le test dans votre débugger pour qu’il fasse une pause avant le point d’arrêt. Faisons cela ensemble :
Comme vous l’avez vu, le débugger a affiché une ligne de code surlignée en haut de l’éditeur. Il affiche aussi un volet de débug dans la partie basse de l’écran. Regardons cela de plus près :
La fenêtre d’explorateur du projet affiche les fichiers du projet, tels que le code Java.
Le point d’arrêt actuel est surligné dans le volet éditeur, vous montrant la ligne de code sur laquelle la JVM a été mise en pause.
L’outil de débug apparaît en bas de votre IDE lorsque vous commencez à débugger une application. Il contient des composants pour vous aider dans le débug.
Le volet Frame affiche la stack trace de votre application, c’est-à-dire la série d’appels de méthodes et les numéros de lignes qui ont conduit au point d’arrêt actuel.
Le volet Variables affiche toutes les variables actuellement délimitées visibles par le code au point d’arrêt actuel.
Les boutons de contrôle d’exécution peuvent être utilisés pour contrôler le flux de votre application. Ce sont les boutons de contrôle à distance et ils déterminent si vous continuez à inspecter votre code au ralenti ou si vous accélérez jusqu’à un autre point.
À gauche du volet Débug, IntelliJ fournit également plusieurs autres outils pratiques pour arrêter et démarrer le débugger. Vous pouvez mettre fin à la session de débug en cliquant sur le bouton Stop (carré rouge).
En utilisant ces commandes, vous pouvez :
Redémarrer la session de débug en cours.
Exécuter à nouveau tous vos tests les plus récents ayant échoué.
Faire en sorte que vos tests s’auto-exécutent lorsqu’ils sont modifiés.
Reprendre l’exécution et cesser la suspension du point d’arrêt actuel.
Mettre en pause une JVM dont la suspension a été stoppée à son point actuel d’exécution.
Stopper totalement le process de débug actuel.
Activer et désactiver différents points d’arrêts à travers votre application.
Ces éléments peuvent être utiles lorsque vous exécutez vos tests avec le débugger. Vous verrez comment utiliser certains d’entre eux plus tard.
Ajoutez des points d’arrêt supplémentaires
Avez-vous déjà exploré une ville que vous ne connaissiez pas bien en vous souvenant d’endroits relatifs à des points de repère comme un cinéma, un restaurant, ou un café ? « Ah oui, c’est le glacier derrière le cinéma. »
Lorsque vous exécutez votre test qui échoue, il crée un parcours, exactement comme un chemin à travers la ville, mais plutôt que de voyager d’étape en étape, vous allez de déclaration en déclaration, entrant dans d’autres méthodes qui se voient appelées.
Dans notre exemple de rapport de bug, l’utilisateur vérifiait la taille de selle d’un dragon en 2020. Comme vous l’avez vu dans nos stack traces, cela implique un voyage à travers plusieurs méthodes :
Soit la méthode, soit le test d’intégration
main()
est habituellement notre premier code à être exécuté.main()
et notre test peuvent alors tous deux appelerDragonSaddleSizeEstimator.estimateSaddleSizeInCentiMeters(2020)
Ceci appelle
com.openclassrooms.debugging.DragonSaddleSizeVerifier.verify(...)
Étant donné que vous êtes maintenant un détective essayant de déterminer la cause d’un bug, est-ce que ce ne serait pas génial si vous pouviez aussi stopper le code à plusieurs endroits pour observer le mystère se dérouler ? Vous pourriez d’abord l’arrêter dans votre test, puis dans la méthode estimateSaddleSizeInCentiMeters, et enfin, dans la méthode verify. En d’autres termes, vous mettez en place plusieurs points d’arrêt.
C’est le même process que précédemment, sauf que vous l’effectuez à plus d’un endroit. Par exemple, vous pouvez cliquer sur la marge à côté de plusieurs lignes dans plusieurs fichiers.
Supposons que l’année que nous avons passée à notre programme soit modifiée à notre insu. L’année est passée entre plusieurs méthodes et il pourrait être logique de vérifier que c’est exactement conforme à ce que nous attendions à chaque pas :
Cela vous permet de débugger à nouveau votre code et de stopper immédiatement au premier point d’arrêt atteint par la JVM. Une fois là, vous pouvez inspecter si vous avez passé vos valeurs correctement dans le code. En cliquant sur resume (reprendre) dans le volet de contrôles d’exécution, vous pouvez permettre à votre application de continuer l’exécution jusqu’au point d’arrêt suivant. Encore une fois, votre code est suspendu. Vous pouvez continuer à cliquer sur resume jusqu’à ce le programme se termine ; dans ce cas, en s’effondrant !
Et maintenant, regardons comment se déplacer entre des points d’arrêt multiples.
En vous déplaçant entre des points d’arrêt, vous pouvez examiner comment les valeurs sont passées entre les méthodes. Donc maintenant, regardons les preuves à date :
Qu’avez-vous appris au cours de cette phase de l’enquête ?
Dans ce cas, il semble clair que l’année ne change pas du tout.
targetYear
était toujours réglé sur 2020 au point oùestimateSaddleSizeInCentiMeters()
a appeléverifier.verify(double saddleSize)
.De plus, la méthode
verifier.verify(double saddleSize)
se voit passer une valeur de -49 par la méthode estimateSaddleSizeInCentiMeters(int targetYear), ce qui implique que nous avons calculé une taille de selle négative bien avant que l’exception ne soit levée.
C’était une investigation de qualité ! Notre théorie selon laquelle la date était modifiée est fausse. Néanmoins, nous avons maintenant les outils nécessaires pour nous arrêter à de multiples endroits pendant que nous enquêtons sur le problème. Le fait de vous déplacer dans le code étape par étape vous a permis de voir les valeurs contenues par les variables à différentes étapes de la vie du programme.
Gérez les points d’arrêt
À mesure que vous ajoutez davantage de points d’arrêt à votre code, il peut devenir difficile de se souvenir où ils se trouvent. Il est particulièrement important de s’en souvenir lorsque vous avez besoin d’enlever ceux qui ne sont plus utiles.
Vous pouvez utiliser IntelliJ pour gérer tous vos points d’arrêt du même endroit, nommé le Breakpoints View (vue des points d’arrêt).
Cliquez droit sur le point d’arrêt rouge et cliquez sur More (plus).
OU cliquez sur le double point rouge pour voir les points d’arrêt depuis l’outil de débug.
Vous pouvez maintenant cocher et décocher les points d’arrêt.
Comme vous le voyez, j’ai décoché le test d’intégration, pour empêcher le débugger de s’y arrêter. J’ai fait cela car le bug semble se situer entre le test et le vérificateur.
En résumé
Un point d’arrêt représente une ligne de code jusqu’à laquelle vous avez dit à la JVM de dérouler l’exécution et ensuite de la suspendre pour que vous puissiez enquêter.
Le débugger peut vous montrer les variables actuellement visibles par et dans le périmètre d’un point d’arrêt où vous êtes arrêté.
Pour vérifier comment les valeurs sont modifiées entre les appels de méthode, placez des points d’arrêt multiples à travers votre code source.
Le débugger vous permet de reprendre à partir de n’importe quel point d’arrêt et suspendra l’activité au prochain point d’arrêt qu’il rencontrera.
La stack trace d’une exception peut vous montrer la chaîne d’appels de méthode menant à votre panne. Utilisez-la pour décider où vous arrêter.
Dans le chapitre suivant, nous allons observer un autre type de point d’arrêt : les points d’arrêt conditionnels !