Fuzz: تست فاز حالا داخل Pest جا میشه
خلاصهٔ کاملتر
نویسنده میگه مدتی سرگرم کار امنیتی تو شرکتش بوده و وقتی باگها رو میدیده به چشمش اومده که چندتاشون با fuzz testing (یعنی ریختن ورودیهای عجیب و خراب به پارسرها و هلپرها تا یه جایی بشکنه) پیدا میشدن. مشکلش این بود که ابزارهای موجود یه دنیای CLI جدا دارن که سالی یه بار یادت میافته سراغشون بری. پس Fuzz رو ساخت: نسخه ۱ پکیج jonpurvis/fuzz که روی nikic/php-fuzzer سوار شده و تست فاز رو میاره وسط سوییت تست عادی Pest.
نکته اصلیاش coverage-guided بودنه، یعنی فازر با این هدایت میشه که هر ورودی کدوم خطهای کد تو رو واقعا اجرا کرده. اگه یه ورودی جهشیافته فقط همون خطهای مسیر خوشبینانه قبلی رو دوباره بزنه، دور انداخته میشه؛ ولی اگه یه دفعه بره تو یه if یا شرط null یا مسیر خطای دیگه، نگه داشته میشه و از همون نسلهای بعدی ساخته میشه. نتیجهش اینه که بودجه اجرا جای هدر رفتن روی نویز، به سمت شکلهای عجیبی میره که واقعا کد رو تحت فشار میذارن.
نویسنده مرز کار رو با dataset های Pest هم روشن میکنه و میگه هر دو جای خودشون رو دارن. dataset رفتار کد رو روی ورودیهایی تایید میکنه که خودت از قبل بهشون فکر کردی و برای رگرسیونهای اسمدار عالیه. Fuzz ولی جستوجو میکنه: چند seed و یه دیکشنری از قطعههای مفید و یه بودجه اجرا میگیره و دنبال کرشهایی میره که تو لیست نکرده بودی، مثل TypeError، تایماوت یا شکلهای خراب JSON. توصیهاش اینه هر دو رو با هم ببری جلو و هر وقت fuzz یه کرش پیدا کرد، همون پیلود رو ببری داخل یه dataset.
مثال خودش یه پارسر وبهوکه که خروجی json_decode رو یه کم بیشتر از حدش باور میکنه. تست فازش این شکلیه:
test('webhook parser never fatals on hostile JSON', function (): void {
fuzz(Closure::fromCallable([PayloadParser::class, 'eventName']))
->seed(['{"event":"checkout.session.completed"}'])
->withDictionary(['{', '}', '[', ']', 'null', 'event', ':', ','])
->runs(2000)
->maxLen(64)
->run();
});اگه چیزی کرش کنه، Pest تست رو فیل میکنه و بهصورت دیفالت پیلود رو زیر .pest/fuzz-crashes/ ذخیره میکنه تا بتونی ریپلیش کنی. توصیه نویسنده اینه که callable استاتیک یا Closure::fromCallable بدی تا ورکر ایزوله راضی بمونه. خودش هم میگه کل پکیج رو تو سفر قطار به منچستر شروع کرده: با AI یه پلن خوندنی درآورده و بعد همون رو اجرا کرده، و کار اصلی و جالب تصمیمگیری درباره این بود که «فاز تستینگ Pest-native» باید چه حسی داشته باشه.
نکات کلیدی:
- پکیج jonpurvis/fuzz نسخه ۱، نصب با composer بهصورت dev dependency
- حداقل PHP 8.4 و Pest 5 لازمه
- موتور زیرینش nikic/php-fuzzer ـه
- پیلود کرشها بهصورت پیشفرض تو .pest/fuzz-crashes/ ذخیره میشه
- تنظیمات اصلی: seed()، withDictionary()، runs()، maxLen() و saveCrashes()
- تست وقتی فیل میشه که تابع هدف Error یا TypeError هندلنشده بده یا تایماوت کنه
- بهتره callable استاتیک پاس بدی تا ورکر ایزوله مشکل نخوره




