Débogage pour grands débutants
Le code que nous écrivons en tant que développeurs de logiciels ne fait pas toujours ce que nous attendions. Il fait parfois quelque chose de totalement différent ! En cas d’imprévu, la tâche suivante consiste à identifier la raison, et bien qu’il soit tentant de rester simplement bouche bée devant notre code pendant des heures, il est plus facile et plus efficace d’utiliser un outil de débogage, ou débogueur.
Malheureusement, un débogueur n’est pas quelque chose qui peut révéler comme par magie tous les problèmes ou « bogues » dans notre code. Déboguer signifie exécuter votre code pas à pas dans un outil de débogage tel que Visual Studio afin de trouver le point exact où vous avez fait une erreur de programmation. Vous comprenez alors les corrections que vous devez effectuer dans votre code, et les outils de débogage vous permettent souvent d’apporter des modifications temporaires afin de pouvoir continuer l’exécution du programme.
L’utilisation efficace d’un débogueur est également une compétence qui nécessite du temps et des efforts, mais il s’agit d’une tâche essentielle que tout développeur de logiciels doit savoir effectuer. Dans cet article, nous allons présenter les principes fondamentaux du débogage et fournir des conseils pour vous aider à démarrer.
Clarifiez le problème en vous posant les bonnes questions
Cela aide d’identifier clairement le problème que vous avez rencontré avant d’essayer de le résoudre. Nous supposons que vous avez déjà rencontré un problème dans votre code, sinon vous ne seriez pas ici à essayer de déterminer comment déboguer ! Par conséquent, avant de commencer le débogage, veillez à bien identifier le problème que vous cherchez à résoudre :
Que devait faire votre code initialement ?
Que s’est-il passé en réalité ?
Si vous rencontrez une erreur (exception) pendant l’exécution de votre application, cela peut être une bonne chose ! Une exception est un événement inattendu rencontré lors de l’exécution de code, généralement une erreur quelconque. Un outil de débogage vous permet d’accéder à l’emplacement exact dans votre code où l’exception s’est produite, et peut vous aider à examiner les solutions possibles.
Si quelque chose d’autre s’est produit, quel est le symptôme du problème ? Avez-vous déjà une idée de l’emplacement où ce problème s’est produit dans votre code ? Par exemple, si votre code affiche du texte, mais que celui-ci est incorrect, vous savez que soit vos données sont incorrectes, soit le code qui définit le texte d’affichage présente un bogue. En parcourant le code pas à pas dans un débogueur, vous pouvez examiner chaque modification apportée à vos variables pour découvrir exactement quand et comment des valeurs incorrectes sont affectées.
Examinez vos hypothèses
Avant d’étudier un bogue ou une erreur, réfléchissez aux hypothèses qui vous ont mené à attendre certains résultats. Des hypothèses cachées ou inconnues peuvent interférer avec l’identification d’un problème même quand vous observez directement la cause du problème dans un débogueur. Il se peut que vous ayez une longue liste d’hypothèses ! Voici quelques questions à se poser pour vous aider à y voir plus clair dans vos hypothèses.
Utilisez-vous la bonne API (autrement dit, l’objet, la fonction, la méthode ou la propriété adéquat) ? Une API que vous utilisez peut ne pas faire ce que vous pensez qu’elle fait. (Une fois que vous avez examiné l’appel d’API dans le débogueur, sa correction peut nécessiter un aller-retour vers la documentation pour aider à identifier l’API correcte.)
Utilisez-vous une API correctement ? Peut-être avez-vous utilisé la bonne API, mais pas de la bonne manière.
Votre code contient-il des fautes de frappe ? Certaines fautes de frappe, comme une simple faute d’orthographe dans le nom d’une variable, peuvent être difficiles à voir, en particulier quand vous travaillez avec des langages qui ne nécessitent pas la déclaration des variables avant leur utilisation.
Avez-vous apporté une modification à votre code, que vous pensez ne pas être liée au problème que vous observez ?
Vous attendiez-vous à ce qu’un objet ou une variable contienne une certaine valeur (ou un certain type de valeur) différente de celle réellement présente ?
Connaissez-vous l’intention du code ? Il est souvent plus difficile de déboguer le code rédigé par quelqu’un d’autre. Si ce n’est pas votre code, vous devrez peut-être consacrer du temps à apprendre ce que fait exactement le code avant de pouvoir le déboguer efficacement.
Conseil
Lors de l’écriture de code, commencez à petite échelle et avec du code qui fonctionne ! (Un bon exemple de code est utile ici.) Parfois, il est plus facile de corriger un ensemble volumineux ou complexe de code en commençant par un petit segment de code qui illustre le but principal que vous voulez atteindre. Ensuite, vous pouvez modifier ou ajouter du code de façon incrémentielle, en effectuant des tests à chaque stade.
Par la remise en question de vos hypothèses, vous pouvez réduire le temps nécessaire pour identifier un problème dans votre code. Vous pourriez également réduire le temps nécessaire pour le corriger.
Parcourez votre code pas à pas en mode débogage pour déterminer où le problème s’est produit.
Quand vous exécutez normalement une application, vous voyez les erreurs et les résultats incorrects uniquement après l’exécution du code. Un programme peut également se terminer de façon inattendue sans vous indiquer pourquoi.
Quand vous exécutez une application dans un débogueur (autrement dit en mode débogage), le débogueur surveille activement tout ce qui se produit durant l’exécution du programme. Cela vous permet également de suspendre l’exécution de l’application à tout moment pour examiner son état, et de parcourir votre code ligne par ligne afin d’observer chaque détail à mesure qu’il se produit.
Dans Visual Studio, vous basculez en mode débogage à l’aide de la touche F5 (ou de la commande de menu Déboguer>Démarrer le débogage ou du bouton Démarrer le débogage dans la barre d’outils Débogage). Si des exceptions se produisent, l’Assistance sur l’exception de Visual Studio vous amène au point exact où l’exception s’est produite et fournit d’autres informations utiles. Pour plus d’informations sur la prise en charge des exceptions dans le code, consultez Techniques et outils de débogage.
Si aucune exception ne s’est produite, vous avez probablement une bonne idée de l’endroit où rechercher le problème dans votre code. C’est à cette étape là que l’on utilise des points d’arrêt avec le débogueur, pour pouvoir examiner le code plus attentivement. Les points d'arrêt constituent une fonctionnalité élémentaire et essentielle de toute procédure de débogage fiable. Quand vous définissez un point d’arrêt, Visual Studio interrompt l’exécution du code à l’emplacement du point d’arrêt pour vous permettre d’examiner les valeurs des variables, le comportement de la mémoire ou la séquence d’exécution du code.
Dans Visual Studio, vous pouvez rapidement définir un point d’arrêt en cliquant dans la marge de gauche en regard d’une ligne de code, ou en plaçant le curseur sur une ligne et en appuyant sur F9.
Pour illustrer ces concepts, nous allons vous guider à travers un exemple de code qui a déjà plusieurs bogues. Nous utilisons C#, mais les fonctionnalités de débogage s’appliquent à Visual Basic, C++, JavaScript, Python et d’autres langages pris en charge. Un exemple de code pour Visual Basic est également fourni, mais les captures d’écran sont en C#.
Créer un exemple d’application (avec des bogues)
Vous allez maintenant créer une application qui comporte quelques bogues.
Visual Studio et la charge de travail Développement .NET Desktop doivent être installés.
Si vous n’avez pas encore installé Visual Studio, accédez à la page Téléchargements Visual Studio pour l’installer gratuitement.
Si vous devez installer la charge de travail, mais que vous avez déjà installé Visual Studio, sélectionnez Outils>Obtenir les outils et fonctionnalités. Visual Studio Installer est lancé. Choisissez la charge de travail Développement .NET Desktop, puis choisissez Modifier.
Ouvrez Visual Studio.
Dans la fenêtre de démarrage, choisissez Créer un projet. Tapez console dans la zone de recherche, sélectionnez C# ou Visual Basic comme langage, puis choisissez Application console pour .NET. Choisissez Suivant. Tapez un nom de projet comme ConsoleApp_FirstApp, puis sélectionnez Suivant.
Choisissez l’infrastructure cible recommandée ou .NET 8, puis sélectionnez Créer.
Si vous ne voyez pas le modèle de projet Application console pour .NET, accédez à Outils>Obtenir les outils et fonctionnalités, qui ouvre Visual Studio Installer. Choisissez la charge de travail Développement .NET Desktop, puis choisissez Modifier.
Visual Studio crée le projet de console, qui apparaît dans l’Explorateur de solutions dans le volet droit.
Dans Program.cs (ou Program.vb), remplacez l’ensemble du code par défaut par le code suivant. (Sélectionnez d’abord l’onglet du langage approprié, C# ou Visual Basic.)
using System; using System.Collections.Generic; namespace ConsoleApp_FirstApp { class Program { static void Main(string[] args) { Console.WriteLine("Welcome to Galaxy News!"); IterateThroughList(); Console.ReadKey(); } private static void IterateThroughList() { var theGalaxies = new List<Galaxy> { new Galaxy() { Name="Tadpole", MegaLightYears=400, GalaxyType=new GType('S')}, new Galaxy() { Name="Pinwheel", MegaLightYears=25, GalaxyType=new GType('S')}, new Galaxy() { Name="Cartwheel", MegaLightYears=500, GalaxyType=new GType('L')}, new Galaxy() { Name="Small Magellanic Cloud", MegaLightYears=.2, GalaxyType=new GType('I')}, new Galaxy() { Name="Andromeda", MegaLightYears=3, GalaxyType=new GType('S')}, new Galaxy() { Name="Maffei 1", MegaLightYears=11, GalaxyType=new GType('E')} }; foreach (Galaxy theGalaxy in theGalaxies) { Console.WriteLine(theGalaxy.Name + " " + theGalaxy.MegaLightYears + ", " + theGalaxy.GalaxyType); } // Expected Output: // Tadpole 400, Spiral // Pinwheel 25, Spiral // Cartwheel, 500, Lenticular // Small Magellanic Cloud .2, Irregular // Andromeda 3, Spiral // Maffei 1, 11, Elliptical } } public class Galaxy { public string Name { get; set; } public double MegaLightYears { get; set; } public object GalaxyType { get; set; } } public class GType { public GType(char type) { switch(type) { case 'S': MyGType = Type.Spiral; break; case 'E': MyGType = Type.Elliptical; break; case 'l': MyGType = Type.Irregular; break; case 'L': MyGType = Type.Lenticular; break; default: break; } } public object MyGType { get; set; } private enum Type { Spiral, Elliptical, Irregular, Lenticular} } }
Notre intention pour ce code consiste à afficher le nom de la galaxie, sa distance et son type dans une même liste. Pour déboguer, il est important de comprendre l’intention du code. Voici le format d’une ligne de la liste que nous souhaitons afficher dans la sortie :
nom de la galaxie, distance, type de galaxie.
Exécuter l’application
Appuyez sur F5 ou sur le bouton Démarrer le débogage dans la barre d’outils Débogage, au-dessus de l’éditeur de code.
L’application démarre et aucune exception n’est signalée par le débogueur. Toutefois, la sortie visible dans la fenêtre de console n’est pas celle à laquelle vous vous attendez. Voici la sortie attendue :
Tadpole 400, Spiral
Pinwheel 25, Spiral
Cartwheel, 500, Lenticular
Small Magellanic Cloud .2, Irregular
Andromeda 3, Spiral
Maffei 1, Elliptical
Toutefois, vous voyez cette sortie à la place :
Tadpole 400, ConsoleApp_FirstApp.GType
Pinwheel 25, ConsoleApp_FirstApp.GType
Cartwheel, 500, ConsoleApp_FirstApp.GType
Small Magellanic Cloud .2, ConsoleApp_FirstApp.GType
Andromeda 3, ConsoleApp_FirstApp.GType
Maffei 1, 11, ConsoleApp_FirstApp.GType
D’après la sortie et notre code, nous savons que GType
est le nom de la classe qui stocke le type de galaxie. Nous essayons d’afficher le type de galaxie (par exemple, « Spiral »), pas le nom de la classe !
Déboguer l’application
L'application étant toujours en cours d'exécution, insérez un point d'arrêt.
Cliquez avec le bouton droit de la souris à côté de la méthode
Console.WriteLine
pour afficher le menu contextuel, puis sélectionnez Point d’arrêt>Insérer un point d’arrêt dans le menu déroulant.foreach (Galaxy theGalaxy in theGalaxies) { Console.WriteLine(theGalaxy.Name + " " + theGalaxy.MegaLightYears + ", " + theGalaxy.GalaxyType); }
Quand vous définissez le point d’arrêt, un point rouge apparaît dans la marge de gauche.
Comme vous constatez un problème dans la sortie, vous commencez le débogage en examinant le code précédent qui définit la sortie dans le débogueur.
Sélectionnez le bouton Redémarrer dans la barre d’outils de débogage (Ctrl + Maj + F5).
L’application s’interrompt au point d’arrêt que vous avez défini. La mise en surbrillance jaune indique où le débogueur est suspendu (la ligne de code jaune n’a pas encore été exécutée).
Placez le curseur sur la variable
GalaxyType
à droite puis, à gauche de l’icône de clé, développeztheGalaxy.GalaxyType
. Vous pouvez constater queGalaxyType
contient une propriétéMyGType
, et que la valeur de propriété est définie surSpiral
.« Spiral » est la valeur correcte que vous attendiez dans la console. Un bon point de départ consiste donc à pouvoir accéder à la valeur dans ce code pendant l’exécution de l’application. Dans ce scénario, nous n’utilisons pas la bonne API. Voyons si vous pouvez corriger cela pendant l’exécution du code dans le débogueur.
Dans le même code, toujours pendant le débogage, placez votre curseur à la fin de
theGalaxy.GalaxyType
et remplacez-le partheGalaxy.GalaxyType.MyGType
. Bien que vous puissiez effectuer la modification, l’éditeur de code signale une erreur indiquant qu’il ne peut pas compiler ce code. (Dans Visual Basic, l’erreur n’est pas affichée et cette section de code fonctionne.)Appuyez sur F11 (Déboguer>Pas à pas détaillé ou le bouton Pas à pas détaillé dans la barre d’outils de débogage) pour exécuter la ligne de code actuelle.
F11 fait avancer le débogueur (et exécute le code) une seule instruction à la fois. F10 (Pas à pas principal) est une commande similaire, et toutes deux sont utiles pour apprendre à utiliser le débogueur.
La boîte de dialogue Modifier et continuer qui s’affiche indique que les modifications ne peuvent pas être compilées.
Note
Pour déboguer l’exemple de code Visual Basic, ignorez les étapes suivantes jusqu’à ce que vous soyez invité à cliquer sur le bouton Redémarrer
Sélectionnez Modifier dans la boîte de message Modifier et Continuer. Un message d’erreur s’affiche maintenant dans la fenêtre Liste d’erreurs. L’erreur indique que
'object'
ne contient pas de définition pourMyGType
.Bien que nous ayons défini chaque galaxie avec un objet de type
GType
(qui a la propriétéMyGType
), le débogueur ne reconnaît pas l’objettheGalaxy
comme un objet de typeGType
. Que se passe-t-il ? Vous devez examiner tout code qui définit le type de galaxie. Vous constatez alors que la classeGType
a indubitablement une propriétéMyGType
, mais quelque chose ne va pas. Le message d’erreur concernantobject
s’avère être l’indice : pour l’interpréteur de langage, le type semble être un objet de typeobject
au lieu d’un objet de typeGType
.En examinant votre code associé à la définition du type de galaxie, vous constatez que la propriété
GalaxyType
de la classeGalaxy
est spécifiée commeobject
au lieu deGType
.public object GalaxyType { get; set; }
Remplacez le code précédent par ce qui suit :
public GType GalaxyType { get; set; }
Sélectionnez le bouton Redémarrer dans la barre d’outils de débogage (Ctrl + Maj + F5) pour recompiler le code et redémarrer.
Maintenant, quand le débogueur s’arrête sur
Console.WriteLine
, vous pouvez pointer surtheGalaxy.GalaxyType.MyGType
et vérifier que la valeur est définie correctement.Supprimez le point d’arrêt en cliquant sur le cercle de point d’arrêt dans la marge de gauche (ou cliquez avec le bouton droit et choisissez Point d’arrêt>Supprimer le point d’arrêt), puis appuyez sur F5 pour continuer.
L’application s’exécute et affiche la sortie. Cela à l’air de fonctionner, mais vous remarquez quelque chose. Vous vous attendiez à ce que la galaxie Small Magellanic Cloud apparaisse comme une galaxie de type Irregular dans la sortie de console, mais aucun type de galaxie n’est affiché.
Tadpole 400, Spiral Pinwheel 25, Spiral Cartwheel, 500, Lenticular Small Magellanic Cloud .2, Andromeda 3, Spiral Maffei 1, Elliptical
Définissez un point d’arrêt sur cette ligne de code avant l’instruction
switch
(avant l’instructionSelect
en Visual Basic).public GType(char type)
Ce code étant celui où le type de galaxie est défini, nous devons l’examiner plus en détail.
Sélectionnez le bouton Redémarrer dans la barre d’outils de débogage (Ctrl + Maj + F5) pour redémarrer.
Le débogueur s’arrête sur la ligne de code où vous avez défini le point d’arrêt.
Pointez sur la variable
type
. Vous voyez la valeurS
(après le code de caractère). Ce qui vous intéresse, c’est une valeurI
, puisque vous savez qu’il s’agit du type de galaxie Irregular.Appuyez sur F5 et pointez à nouveau sur la variable
type
. Répétez cette étape jusqu’à voir la valeurI
dans la variabletype
.Appuyez à présent sur F11 (Déboguer>Pas à pas détaillé).
Appuyez sur F11 jusqu’à vous arrêter sur une ligne de code dans l’instruction
switch
pour une valeur « I » (instructionSelect
dans Visual Basic). Vous constatez ici un problème évident résultant d’une faute de frappe. Vous vous attendiez à ce que le code accède à l’emplacement où il définitMyGType
comme type de galaxie Irregular, mais au lieu de cela le débogueur ignore complètement ce code et s’arrête à la sectiondefault
de l’instructionswitch
(instructionElse
dans Visual Basic).En examinant le code, vous voyez une faute de frappe dans l’instruction
case 'l'
. Elle doit avoir la valeurcase 'I'
.Sélectionnez le code pour
case 'l'
et remplacez-le parcase 'I'
.Supprimez votre point d’arrêt, puis sélectionnez le bouton Redémarrer pour redémarrer l’application.
Les bogues sont maintenant corrigés et vous voyez la sortie attendue.
Appuyez sur n’importe quelle touche pour fermer l’application.
Résumé
Quand vous constatez un problème, utilisez le débogueur et les commandes de pas à pas telles que F10 et F11 pour rechercher la région de code où se trouve le problème.
Notes
Si son identification est difficile, définissez un point d’arrêt dans le code qui s’exécute avant le moment où le problème se produit, puis utilisez les commandes de pas à pas jusqu’à ce que le problème se manifeste. Vous pouvez également utiliser des points de trace pour enregistrer des messages dans la fenêtre Sortie. En examinant les messages enregistrés (et en observant ceux qui n’ont pas encore été enregistrés), vous pouvez souvent isoler la région de code présentant un problème. Vous devrez peut-être répéter ce processus plusieurs fois afin de localiser l’emplacement précis du problème.
Une fois identifiée la région de code à problème, utilisez le débogueur pour l’examiner. Pour rechercher la cause d’un problème, inspectez le code défectueux tout en exécutant votre application dans le débogueur :
Inspectez les variables et vérifiez si elles contiennent le type de valeur prévu. Si vous trouvez une valeur incorrecte, recherchez où elle a été définie (vous devrez peut-être pour cela redémarrer le débogueur, examiner la pile des appels, ou les deux).
Vérifiez si votre application exécute le code prévu. (Par exemple, dans l’exemple d’application, nous nous attendions à ce que le code pour l’instruction
switch
affecte la valeur Irregular comme type de galaxie, mais l’application a ignoré le code à cause de la faute de frappe.)
Conseil
Vous utilisez un débogueur pour vous aider à trouver des bogues. Un outil de débogage peut trouver des bogues à votre place uniquement s’il connaît l’intention de votre code. Un outil ne peut avoir connaissance de l’intention de votre code que si vous, le développeur, exprimez cette intention. Vous devez pour cela écrire des tests unitaires.
Étapes suivantes
Dans cet article, vous avez découvert quelques concepts généraux liés au débogage. Vous pouvez à présent en découvrir plus sur le débogueur.