Aller au contenu

Déboguer un test en échec avec un agent

Ce guide montre comment amener un agent à utiliser un débogueur sur une défaillance que les instructions d’affichage n’expliquent pas.

L’outil debug pilote une véritable session Debug Adapter Protocol. Une trame arrêtée répond d’un coup à toutes les questions sur ce moment — chaque variable locale, chaque appelant et une expression évaluée dans la portée propre à la trame — là où une instruction d’affichage ne répond qu’à la question que vous avez pensé à poser avant de lancer.

L’outil reste présent dans la surface d’outils pour que l’agent puisse demander pourquoi rien n’est utilisable plutôt que de deviner. Un adaptateur ne peut réellement démarrer que lorsque les deux conditions suivantes sont réunies :

  • un marqueur de projet dans le checkout, et
  • le binaire de l’adaptateur qui se résout.

Demandez à l’agent de vérifier :

debug(op: "adapters")

Il répond avec ce qu’il a trouvé, ou explique qu’un adaptateur a besoin des deux volets.

Langage Adaptateur Marqueur Installation
Dart / Flutter dart debug_adapter pubspec.yaml Fourni avec le SDK — rien à faire
Python python3 -m debugpy.adapter pyproject.toml, setup.py, requirements.txt pip install debugpy
Rust / C / C++ lldb-dap Cargo.toml, CMakeLists.txt Fourni avec LLVM
Go dlv dap go.mod go install github.com/go-delve/delve/cmd/dlv@latest

L’ordre compte, et l’outil l’impose : les points d’arrêt peuvent être posés avant qu’une session existe, parce que c’est la séquence qu’exige le protocole.

Demandez à l’agent quelque chose comme :

La fonction compute dans bin/main.dart renvoie une valeur erronée. Pose un point d’arrêt sur la ligne qui affecte product, lance-la sous le débogueur et dis-moi ce que valent réellement a et b.

Il exécutera à peu près :

debug(op: "breakpoints", file: "bin/main.dart", lines: [7])
debug(op: "launch", program: "bin/main.dart")

Le lancement indique où l’exécution s’est arrêtée :

Launched bin/main.dart on dart (session dart-1). Stopped: breakpoint. Use `stack` to see where.
debug(op: "stack")
→ #1 compute (bin/main.dart:7:3)
#2 main (bin/main.dart:2:18)

Puis descendez dans la trame :

debug(op: "scopes", frame_id: 1)
→ Locals (reference 12)
debug(op: "variables", reference: 12)
→ a (int) = 6
b (int) = 7
product (int) = 42

Un objet qui a des enfants signale [expand: reference N] — mais seulement lorsqu’il y a réellement quelque chose derrière, de sorte qu’une expansion que l’agent ne peut pas utiliser ne lui est jamais proposée.

Pour tout ce qui n’est pas visible comme variable locale :

debug(op: "evaluate", expression: "config.timeout.inSeconds", frame_id: 1)
Ce que vous voulez Opération
Exécuter jusqu’au prochain arrêt continue
Ligne suivante, même trame step_over
Entrer dans l’appel step_in
Sortir vers l’appelant step_out
Arrêter un programme en cours d’exécution pause

S’attacher à un processus déjà en cours d’exécution

Section intitulée “S’attacher à un processus déjà en cours d’exécution”

Pour un processus bloqué plutôt qu’un processus que vous lancez :

debug(op: "attach", port: 5858)
debug(op: "terminate")

Terminez toujours la session. Un adaptateur de débogage possède un processus arrêté qui retient tout ce que ce processus retient — un port, un verrou, une connexion à une base de données.

Une expansion de variables sur un graphe d’objets profond est illimitée par nature — un seul widget Flutter atteint tout l’arbre d’éléments. Les enfants par portée sont plafonnés à 50, les valeurs à 400 caractères et les trames de pile à 30. Un résultat d’outil qui remplit la fenêtre de contexte est un outil qui met fin à l’exécution qu’il aidait.