Saltar para o conteúdo

Depurar um teste com falha com um agente

Este guia mostra-lhe como fazer com que um agente use um depurador numa falha que as instruções de impressão não conseguem explicar.

A ferramenta debug conduz uma sessão real do Debug Adapter Protocol. Um frame parado responde a todas as perguntas sobre aquele momento de uma só vez — cada variável local, cada chamador e uma expressão avaliada no próprio âmbito do frame — enquanto uma instrução de impressão responde apenas à pergunta que pensou em fazer antes de executar.

A ferramenta permanece à superfície para que o agente possa perguntar porque é que nada é utilizável, em vez de adivinhar. Um adaptador só consegue realmente arrancar quando ambas as condições seguintes se verificam:

  • um marcador de projeto no checkout, e
  • o binário do adaptador a resolver.

Peça ao agente para verificar:

debug(op: "adapters")

Responde com o que encontrou, ou explica que um adaptador precisa das duas metades.

Linguagem Adaptador Marcador Instalação
Dart / Flutter dart debug_adapter pubspec.yaml Vem com o SDK — nada a fazer
Python python3 -m debugpy.adapter pyproject.toml, setup.py, requirements.txt pip install debugpy
Rust / C / C++ lldb-dap Cargo.toml, CMakeLists.txt Vem com o LLVM
Go dlv dap go.mod go install github.com/go-delve/delve/cmd/dlv@latest

Defina primeiro o ponto de interrupção e só depois inicie

Secção intitulada “Defina primeiro o ponto de interrupção e só depois inicie”

A ordem é importante e a ferramenta impõe-a: os pontos de interrupção podem ser definidos antes de existir uma sessão, porque é essa a sequência que o protocolo exige.

Peça ao agente algo como:

A função compute em bin/main.dart devolve o valor errado. Defina um ponto de interrupção na linha que atribui product, inicie-o sob o depurador e diga-me o que são realmente a e b.

Irá executar aproximadamente:

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

O arranque indica onde parou:

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)

Depois entre nele:

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

Um objeto com filhos indica [expand: reference N] — mas só quando há genuinamente algo por trás dele, pelo que uma expansão que o agente não consegue usar nunca é oferecida.

Para algo que não seja visível como variável local:

debug(op: "evaluate", expression: "config.timeout.inSeconds", frame_id: 1)
O que pretende Operação
Executar até à próxima paragem continue
Linha seguinte, mesmo frame step_over
Entrar na chamada step_in
Sair para o chamador step_out
Parar um programa em execução pause

Para um processo encravado, em vez de um que está a iniciar:

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

Termine sempre a sessão. Um adaptador de depuração é dono de um processo parado que detém tudo o que esse processo detém — uma porta, um bloqueio, uma ligação a uma base de dados.

Uma expansão de variables sobre um grafo de objetos profundo é, por natureza, ilimitada — um único widget do Flutter alcança toda a árvore de elementos. Os filhos por âmbito estão limitados a 50, os valores a 400 caracteres e os frames de pilha a 30. Um resultado de ferramenta que enche a janela de contexto é uma ferramenta que acaba com a execução que estava a ajudar.