اشکالزدایی تست ناموفق با یک عامل
این راهنما نشان میدهد چگونه از یک عامل بخواهید روی شکستی که دستورهای print آن را توضیح نمیدهند، از یک اشکالزدا استفاده کند.
ابزار debug یک نشست واقعی Debug Adapter Protocol را هدایت میکند. یک فریم متوقفشده همزمان به همهٔ پرسشها دربارهٔ آن لحظه پاسخ میدهد — هر متغیر محلی، هر فراخوان، و عبارتی که در حوزهٔ خودِ فریم ارزیابی میشود — در حالی که یک دستور print تنها به پرسشی پاسخ میدهد که پیش از اجرا به ذهنتان رسیده بود.
پیش از شروع
بخش با عنوان “پیش از شروع”این ابزار روی سطح باقی میماند تا عامل بتواند بپرسد چرا هیچچیز قابلاستفاده نیست، بهجای اینکه حدس بزند. یک آداپتور تنها زمانی واقعاً میتواند آغاز به کار کند که هر دو مورد زیر برقرار باشند:
- یک نشانگر پروژه در چکاوت، و
- پیدا شدن باینری آداپتور.
از عامل بخواهید بررسی کند:
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 به کل درخت عناصر میرسد. فرزندان هر حوزه حداکثر ۵۰ مورد، مقادیر حداکثر ۴۰۰ نویسه و فریمهای پشته حداکثر ۳۰ مورد محدود شدهاند. نتیجهٔ ابزاری که پنجرهٔ بافت را پر کند، ابزاری است که همان نوبتی را که داشت کمکش میکرد پایان میدهد.
مرتبط
بخش با عنوان “مرتبط”- هوش کد — چرا اشکالزدا، کامپایلر و تطبیقدهنده هرکدام به پرسش متفاوتی پاسخ میدهند
- ابزارهای داخلی عامل — هر عملیات و آرگومان
debug - عیبیابی یک عامل — وقتی مشکل خودِ عامل است، نه کد