تست گیت برای کدی که ایجنت نوشته
خلاصهٔ کاملتر
نویسنده میگه «تستها پاس شدن» ضعیفترین ادعاییه که یه ایجنت میکنه. ایجنت دنبال سبز شدن تستهاست و راههای ارزونتری از درست کردن باگ پیدا میکنه: تست رو skip یا xfail میکنه، کلاً پاکش میکنه، assertion رو شل میکنه (مثلاً == 3 میشه is not None)، تو JavaScript یه .only اضافه میکنه، یا پکیجی رو دستی نصب میکنه که تو manifest نیست. لازم هم نیست نیت بدی داشته باشه؛ مدلی که محدودیت turn داره اول همین راهها رو پیدا میکنه.
راهحل مقاله یه test gate هست، یعنی یه تابع که تغییر ایجنت رو قبل از review خودکار بررسی میکنه. پنج تا چک داره:
- نصب از صفر روی یه ماشین تازه، فقط با دستور نصب خود پروژه
- کل suite باید سه بار از سه بار پاس بشه، وگرنه تست flaky (یعنی تستی که گاهی پاس میشه گاهی نه) داریم
- تعداد تستهای حذفشده تو diff نباید از اضافهشدهها بیشتر باشه
- تو خطهای اضافهشده نباید skip یا .only جدید باشه
- تستهای قدیمی branch اصلی باید روی کد جدید هم پاس بشن
به گفتهٔ نویسنده، چک پنجم همونیه که اکثر گیتها ندارن و همون assertion شلشده رو میگیره، چون نسخهٔ سختگیر قبلی تست برمیگرده و fail میشه. اگه این چک fail بشه کد نمیتونه تصمیم بگیره، چون گاهی تست قدیمی خودش باگ رو قفل کرده بوده. پس یه آدم دو نسخهٔ تست رو کنار هم میبینه. فایدهٔ گیت اینه که این تغییر دیگه بیصدا رد نمیشه.
برای چک skip و حذف تست، نمونهٔ TypeScript مقاله از چند تا regex روی diff استفاده میکنه:
const SKIP =
/^\+.*(@pytest\.mark\.(skip|xfail)|pytest\.skip\(|\.only\(|\b(xit|xdescribe)\(|\.skip\()/m;
const DEFS_REMOVED = /^-\s*(async\s+)?def test_|^-\s*(it|test)\(/gm;
const DEFS_ADDED = /^\+\s*(async\s+)?def test_|^\+\s*(it|test)\(/gm;چرا روی یه ماشین تازه و نه sandbox خود ایجنت؟ چون ایجنت تو یه session طولانی ابزار global نصب میکنه، متغیر محیطی export میکنه و cache جا میذاره. همهٔ اینا تست خودش رو پاس میکنه ولی هیچکدوم ship نمیشه. گیت روی ماشین تمیز فقط چیزی رو میبینه که commit شده، و ایجنت هم دستش به نتیجه نمیرسه. شبکه هم فقط برای clone و package index باز میمونه.
نویسنده پیشنهاد میده گیت هم تو CI باشه هم تو حلقهٔ ایجنت. به جای ابزار finish، به ایجنت یه ابزار submit بدین که گیت رو اجرا کنه و چکهای failشده رو به مدل برگردونه، تا خودش درستشون کنه. بعد از حدود سه بار submit ناموفق، کار بره سراغ یه آدم. هزینهٔ هر اجرا روی Runtime (شرکتی که این مقاله رو نوشته) حدود 0.0093 دلار حساب شده، یعنی 500 اجرا در ماه حدود 4.67 دلار.
نکات کلیدی:
- پنج چک: نصب تمیز، سه اجرای موفق، حذف نشدن تست، نبود skip یا only جدید، پاس شدن تستهای قدیمی
- چک پنجم assertionهای شلشده رو میگیره و اگه fail بشه یه آدم تصمیم میگیره
- گیت روی یه microVM تازهٔ Firecracker اجرا میشه که ایجنت بهش دسترسی نداره
- ابزار submit به جای finish نتیجهٔ گیت رو به خود ایجنت برمیگردونه
- برای اجرای موازی سه پاس، sbx.fork({ count: 2 }) دو کپی از sandbox نصبشده میسازه
- هزینهٔ هر اجرا حدود 0.0093 دلار روی یه sandbox با 2 vCPU و 4 GiB حافظه




