ข้ามไปยังเนื้อหา

ดีบักการทดสอบที่ล้มเหลวด้วยเอเจนต์

คู่มือนี้แสดงวิธีทำให้เอเจนต์ใช้ดีบักเกอร์กับความล้มเหลวที่คำสั่งพิมพ์อธิบายไม่ได้

เครื่องมือ debug ขับเคลื่อนเซสชัน Debug Adapter Protocol จริง เฟรมที่ถูกหยุดไว้จะตอบทุกคำถามเกี่ยวกับขณะนั้นพร้อมกันในครั้งเดียว — ตัวแปรโลคอลทุกตัว ผู้เรียกทุกชั้น และนิพจน์ที่ประเมินในสโคปของเฟรมเอง — ในขณะที่คำสั่งพิมพ์ตอบได้แค่คำถามที่คุณคิดจะถามก่อนรัน

เครื่องมือนี้ยังคงอยู่บนพื้นผิว เพื่อให้เอเจนต์ถามได้ว่าทำไมจึงใช้งานอะไรไม่ได้ แทนที่จะเดา อะแดปเตอร์จะเริ่มทำงานได้จริงก็ต่อเมื่อเข้าเงื่อนไข ทั้งสอง ข้อนี้:

  • มีมาร์กเกอร์โปรเจกต์อยู่ในเช็กเอาต์ และ
  • ค้นหาไบนารีของอะแดปเตอร์เจอ

ลองให้เอเจนต์ตรวจสอบ:

debug(op: "adapters")

มันจะตอบด้วยสิ่งที่พบ หรืออธิบายว่าอะแดปเตอร์ต้องมีครบทั้งสองส่วน

ภาษา อะแดปเตอร์ มาร์กเกอร์ การติดตั้ง
Dart / Flutter dart debug_adapter pubspec.yaml มาพร้อม SDK — ไม่ต้องทำอะไร
Python python3 -m debugpy.adapter pyproject.toml, setup.py, requirements.txt pip install debugpy
Rust / C / C++ lldb-dap Cargo.toml, CMakeLists.txt มาพร้อม LLVM
Go dlv dap go.mod go install github.com/go-delve/delve/cmd/dlv@latest

ลำดับสำคัญ และเครื่องมือนี้บังคับใช้มัน: ตั้งเบรกพอยต์ได้ก่อนที่เซสชันจะเกิดขึ้น เพราะนั่นคือลำดับที่โปรโตคอลกำหนดไว้

ลองสั่งเอเจนต์ประมาณนี้:

ฟังก์ชัน compute ใน bin/main.dart คืนค่าผิด ตั้งเบรกพอยต์ที่บรรทัดที่กำหนดค่าให้ product เปิดมันภายใต้ดีบักเกอร์ แล้วบอกฉันว่าจริง ๆ แล้ว a กับ b เป็นเท่าไร

มันจะรันประมาณนี้:

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

การเปิดโปรแกรมจะรายงานว่าหยุดที่ไหน:

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)

จากนั้นไล่เข้าไปข้างใน:

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

ออบเจกต์ที่มีสมาชิกลูกจะรายงาน [expand: reference N] — แต่เฉพาะเมื่อมีอะไรอยู่ข้างหลังจริง ๆ เท่านั้น การขยายที่เอเจนต์ใช้งานไม่ได้จึงไม่ถูกเสนอให้เลย

สำหรับอะไรก็ตามที่มองไม่เห็นในฐานะตัวแปรโลคอล:

debug(op: "evaluate", expression: "config.timeout.inSeconds", frame_id: 1)
สิ่งที่ต้องการ อ็อป
รันไปจนถึงจุดหยุดถัดไป continue
บรรทัดถัดไป เฟรมเดิม step_over
เข้าไปในการเรียก step_in
ออกไปยังผู้เรียก step_out
หยุดโปรแกรมที่กำลังรัน pause

สำหรับโปรเซสที่ค้างอยู่ แทนที่จะเป็นโปรเซสที่คุณกำลังเริ่ม:

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

ปิดเซสชันเสมอ อะแดปเตอร์ดีบักเป็นเจ้าของโปรเซสที่ถูกหยุดไว้ซึ่งยึดอะไรก็ตามที่โปรเซสนั้นยึดอยู่ — พอร์ต ล็อก หรือการเชื่อมต่อฐานข้อมูล

การขยาย variables บนกราฟออบเจกต์ที่ลึกนั้นไร้ขอบเขตโดยธรรมชาติ — วิดเจ็ต Flutter ตัวเดียวแตะถึงทรีอิลิเมนต์ทั้งต้น จำนวนสมาชิกลูกต่อสโคปถูกจำกัดไว้ที่ 50 ค่าต่าง ๆ ที่ 400 ตัวอักษร และเฟรมสแตกที่ 30 ผลลัพธ์ของเครื่องมือที่ถมเต็มหน้าต่างบริบทคือเครื่องมือที่ทำให้การรันที่มันกำลังช่วยอยู่ต้องจบลง