بازگشت به مهندسی مدرن و کار با هوش مصنوعی · فصل ۳ — Repository، Root Cause، Testing و Verification · 17
راهبرد آزمون: واحد، یکپارچه، سرتاسری، پسرفت و پذیرش
تست را بیشتر به اجرای check یا coverage تقلیل میدهد و هنوز risk، oracle و transfer را به evidence وصل نمیکند. موضوع جاری: «راهبرد آزمون: واحد، یکپارچه، سرتاسری، پسرفت و پذیرش». میتواند برای «راهبرد آزمون: واحد، یکپارچه، سرتاسری، پسرفت و پذیرش» strategy آزمون و evidence متناسب با ریسک طراحی و محدودیت آن را توضیح دهد.
خلاصهٔ درس
تست را بیشتر به اجرای check یا coverage تقلیل میدهد و هنوز risk، oracle و transfer را به evidence وصل نمیکند. موضوع جاری: «راهبرد آزمون: واحد، یکپارچه، سرتاسری، پسرفت و پذیرش».
میتواند برای «راهبرد آزمون: واحد، یکپارچه، سرتاسری، پسرفت و پذیرش» strategy آزمون و evidence متناسب با ریسک طراحی و محدودیت آن را توضیح دهد.
خروجی این درس
میتواند برای «راهبرد آزمون: واحد، یکپارچه، سرتاسری، پسرفت و پذیرش» strategy آزمون و evidence متناسب با ریسک طراحی و محدودیت آن را توضیح دهد.
از ریسک شروع کن، نه از نام لایه
یک تغییر کوچک در سرویس قیمتگذاری را در نظر بگیر. این تغییر سه ناحیه را لمس میکند: یک تابع خالص برای محاسبه مبلغ، یک آداپتر ذخیرهسازی و سیمکشی API به سرویس. در شرح تغییر چهار نگرانی مشخص شده است: گردکردن مبلغ نباید عوض شود، رکورد ذخیرهشده باید قرارداد داده را حفظ کند، درخواست API باید واقعاً مسیر جدید را صدا بزند و یک خطای تاریخی نباید دوباره ظاهر شود. علاوه بر این، یک قاعده تأییدشده برای پذیرش نتیجه وجود دارد.
وسوسه رایج این است که قبل از تحلیل ریسک، یک «هرم» یا نسبت ثابت برای تعداد تستها انتخاب کنیم. این درس چنین نسبتی را تجویز نمیکند. خروجی مورد انتظار، Risk-Based Test Strategy Record v1 است: رکوردی که برای هر ریسک، شکست قابل مشاهده، مرز آزمون، مرجع oracle، fixture، sensor، هدف آزمون، بدهبستان و ریسک باقیمانده را روشن میکند.
این درس حدود ۸۵ دقیقه فعالیت فعال دارد. اگر میتوانی از یک change surface واقعی، seamهای مهم را تشخیص دهی، پیشنیاز سخت لازم را داری. اگر تشخیص seam برایت شکننده است، فقط همان بخش لازم از تحلیل محدوده تغییر را ترمیم کن. برای انتخاب مرجع انتظار نیز انضباط بررسی منبع مفید است؛ اما این درس قرار نیست روش بررسی مستندات را دوباره آموزش دهد.
قول محدود این درس: میتوانی یک سبد شواهد متناسب با ریسک طراحی کنی و توضیح بدهی هر sensor چه چیزی را میسنجد، چه چیزی را نمیسنجد و چرا برای تصمیم انسانی کافی یا ناکافی است. این درس اثبات «درستی مطلق سیستم»، یک نسبت بهینه جهانی، برتری ذاتی E2E یا مساویبودن acceptance با E2E را ادعا نمیکند.
مسیر مناسب را انتخاب کن
سه مسیر آموزشی به یک معیار نهایی میرسند:
- Foundation: تعریفها، یک ردگیری کامل و یک رکورد نیمهساختاریافته را طی کن.
- Repair: اگر در تشخیص مرز، oracle یا تفاوت purpose و boundary خطا داری، فقط همان بخش را با counterexample ترمیم کن.
- Experienced / Fast Path: اگر مفهومها را از قبل مسلطی، توضیحهای تکراری را کوتاه کن و مستقیم به تمرین مستقل برو؛ اما artifact، ابعاد بحرانی، تصمیم انسانی و transfer حذف نمیشوند.
یک تشخیص کوتاه: برای سناریوی افتتاحیه، پاسخ بده «آزمون regression» نامِ یک مرز فنی است یا یک هدف؟ سپس برای یک تست سبز بگو مرجع انتظار آن از کجا آمده است. در پایان، یک ریسک را نام ببر که unit test ممکن است اصولاً seam لازم برای دیدن آن را لمس نکند. اگر پاسخها روشن نیستند، مسیر Foundation مناسبتر است.
مدل ذهنی: زنجیره شواهد
راهبرد آزمون را به شکل این زنجیره بخوان:
ریسک → شکست قابل مشاهده → مرز → fixture → oracle → sensor → نتیجه → تصمیم انسانی → ریسک باقیمانده
ریسک پیامد مهمی است که نمیخواهیم بدون شواهد رها شود. شکست قابل مشاهده چیزی است که اگر ریسک واقع شود، میتوان آن را دید یا اندازه گرفت. مرز آزمون تعیین میکند چه اجزایی واقعاً در اجرا حضور دارند. fixture وضعیت و داده کنترلشدهای است که آزمون را تکرارپذیر میکند. oracle مبنایی است که میگوید رفتار مشاهدهشده قابل قبول است یا نه. sensor خودِ آزمون یا probeی است که مشاهده را تولید میکند. نتیجه sensor هنوز تصمیم نیست؛ یک انسان باید قدرت شواهد و محدودیتهای آن را ارزیابی کند.
Unit/local، integration و end-to-end عمدتاً درباره مرز اجرا و realism هستند. Regression و acceptance عمدتاً درباره purpose و authority هستند. یک regression میتواند محلی باشد اگر خطای تاریخی در همان seam محلی رخ داده باشد. یک acceptance check نیز لزوماً نباید تمام UI، شبکه و زیرساخت را اجرا کند؛ باید قاعده پذیرفتهشده را در مرزی بسنجد که برای آن claim کافی است.
Oracle را با assertion اشتباه نگیر. عبارت assert total == 64.35 فقط مکانیزم مقایسه است. سؤال اصلی این است که چرا 64.35 انتظار معتبر است. ممکن است مرجع، قاعده کسبوکار تأییدشده، invariant دامنه، قرارداد آداپتر یا رکورد خطای تاریخی باشد. اگر expected value را فقط با خروجی فعلی برنامه برابر کنی، تست میتواند سبز بماند و در عین حال همان خطا را تأیید کند.
لایه پایه: از هر ریسک یک ردیف قابل بازبینی بساز
برای هر ریسک، قبل از نوشتن test file چهار سؤال را ببند:
- اگر این ریسک واقع شود، دقیقاً چه failure observableی میبینیم؟
- ارزانترین مرزی که seam لازم را واقعاً اجرا میکند چیست؟
- چه authorityی انتظار را معتبر میکند؟
- بعد از این sensor چه blind spotی باقی میماند؟
اصل «ارزانترین sensor قابل اعتماد» به معنی «همیشه unit» نیست. اگر ریسک مربوط به serialization در آداپتر persistence است، تست تابع خالص ارزان است ولی seam درست را اجرا نمیکند. اگر ریسک فقط یک invariant محاسباتی در تابع خالص است، اجرای مرورگر، API، دیتابیس و شبکه realism اضافهای ایجاد میکند که برای آن claim خاص لازم نیست و localization شکست را کندتر میکند.
Coverage نیز فقط اطلاعاتی درباره اجرای ساختار کد میدهد. Coverage بالا نمیگوید oracle درست بوده، داده مرزی مناسب بوده یا seam واقعی اجرا شده است. بنابراین coverage میتواند یک signal کمکی باشد، نه جانشین زنجیره ریسک تا تصمیم.
در Risk-Based Test Strategy Record، هر ردیف باید آنقدر صریح باشد که reviewer بتواند بفهمد «این تست برای کدام ریسک است؟»، «چرا این boundary؟»، «این expected value به چه authority متصل است؟» و «چه چیزی هنوز پوشیده نشده؟».
توضیح عمیق: یک portfolio متناسب با seamها
ماتریس زیر یک نمونه استدلال برای سناریوی درس است، نه نسخهای برای کپیکردن و نه نسبت هدف.
| ریسک | شکست قابل مشاهده | مرز | مرجع oracle | fixture | sensor | هدف | بدهبستان | ریسک باقیمانده |
|---|---|---|---|---|---|---|---|---|
| تغییر رفتار گردکردن مبلغ | اختلاف یک سنت در ورودی مرزی | تابع خالص | invariant دامنه و قاعده گردکردن تأییدشده | مقادیر اعشاری مرزی | تست محلی | تشخیص تغییر رفتار | سریع و دقیق در localization | persistence و wiring را نمیسنجد |
| خرابی serialization در ذخیرهسازی | رکورد ذخیرهشده field/value نادرست دارد | سرویس + آداپتر + store موقت | قرارداد آداپتر | store حافظهای کنترلشده | تست integration | سنجش seam داده | realism بالاتر از تست خالص | مسیر API خارج از مرز است |
| سیمکشی اشتباه API | درخواست معتبر به منطق درست نمیرسد | handler/API + سرویس | قرارداد interface و behavior سرویس | درخواست محلی | sensor یکپارچه نزدیک مرز API | سنجش wiring | seam واقعی را میبیند؛ کندتر از local | UI و deployment واقعی را ثابت نمیکند |
| بازگشت خطای تاریخی | ورودی ثبتشده دوباره نتیجه غلط میدهد | همان seam مسبب خطای قبلی | رکورد خطای تاریخی | reproduction ثبتشده | regression sensor | جلوگیری از recurrence مشخص | متمرکز و قابل توضیح | خطاهای تاریخیِ ثبتنشده را پوشش نمیدهد |
| انطباق با قاعده پذیرش | نتیجه سرویس با rule مصوب ناسازگار است | مرز سرویس کافی برای claim | قاعده پذیرش تأییدشده | سناریوی پذیرش | acceptance check | تصمیم درباره پذیرش رفتار | authority روشن و اجرای کمهزینه | تجربه مرورگر و زیرساخت خارج از claim است |
نکته مهم این است که دو محور را مخلوط نکنیم. «Integration» درباره چیزهایی است که با هم اجرا میشوند. «Regression» درباره دلیل نگهداری یک sensor برای جلوگیری از بازگشت رفتار معیوب است. یک تست میتواند هم integration باشد و هم regression purpose داشته باشد. «Acceptance» نیز authority تصمیم را مشخص میکند؛ سطح فنی را بهتنهایی تعیین نمیکند.
تصویر آموزشی TST001-A01 همین زنجیره را بدون درصد لایه نشان میدهد. اگر تصویر در دسترس نباشد، متن معادل آن چنین است: از یک ریسک شروع کن؛ failure observable را نام ببر؛ boundary را فقط آنقدر گسترش بده که seam لازم اجرا شود؛ fixture را کنترل کن؛ oracle authority را ثبت کن؛ sensor را اجرا کن؛ نتیجه را با محدودیتش تفسیر کن؛ انسان تصمیم بگیرد؛ blind spot باقیمانده را آشکار نگه دار.
مثالهای حلشده
مثال ۱: rounding در تابع خالص
فرض کن تغییر فقط شیوه گردکردن مبلغ را لمس کرده است. ریسک، اختلاف مالی در نقاط اعشاری مرزی است. یک local sensor با چند مقدار مرزی میتواند seam مربوط را مستقیم اجرا کند. broad test ممکن است همان رفتار را هم ببیند، اما وقتی شکست رخ دهد اجزای بیشتری در مسیر دارد و عیبیابی را سختتر میکند. اگر claim فقط درباره قاعده گردکردن است، مرز کوچکتر evidence دقیقتری میدهد.
مثال ۲: all-E2E در برابر portfolio ریسکمحور
یک تیم برای هر چهار ریسک سناریو فقط E2E مینویسد. این انتخاب ممکن است برخی failureها را ببیند، اما feedback کندتر، fixture پیچیدهتر و localization ضعیفتری دارد. در طرف مقابل، تیمی که فقط unit test دارد persistence و wiring را اصولاً اجرا نمیکند. نتیجه مطلوب «میانه عددی» نیست؛ ترکیبی است که برای هر ریسک seam لازم را اجرا کند و هزینه/کوری آن را ثبت کند.
مثال ۳: تست سبز با oracle غلط
یک defect باعث میشود نتیجه ۶۴٫۴۷ به ۶۴٫۴۶ تبدیل شود. توسعهدهنده expected value را به ۶۴٫۴۶ تغییر میدهد چون «برنامه الان همین را میدهد». تست سبز میشود، اما authority انتظار از بین رفته است. repair درست این است که expected value را به rule یا invariant معتبر وصل کنیم و سپس کد را نسبت به آن بسنجیم.
مثال ۴: تغییر مرز persistence
در نسخه بعدی، persistence از یک آداپتر in-process به یک سرویس محلی جدا منتقل میشود. ریسک «ذخیره صحیح quote» باقی است، اما seam تغییر کرده است. ممکن است local sensor محاسبه بدون تغییر بماند؛ integration sensor ذخیرهسازی باید مرزش را جابهجا کند. انتقال مهارت یعنی همین: sensor را بر اساس risk و seam جدید بازطراحی کن، نه اینکه test file قبلی را بیتغییر کپی کنی.
میانبرهای فریبنده و نحوه رد آنها
«۷۰/۲۰/۱۰ همیشه معماری درست است.» این جمله از context سیستم، ریسک و اقتصاد feedback مستقل است. اگر یک ratio تاریخی بهعنوان heuristic دیدهای، آن را hypothesis شروع بدان؛ معیار پذیرش درس نیست.
«E2E قویترین تست است چون واقعیتر است.» realism فقط یک بُعد است. broader boundary میتواند failure را ببیند اما localization بدتری بدهد یا fixture شکنندهتری داشته باشد. قوت evidence به تناسب با claim، oracle و seam بستگی دارد.
«همه تستها سبزند، پس تغییر درست است.» سبز بودن فقط میگوید observed result با expected value تعریفشده برابر شده است. اگر expected value authority ندارد یا risk مهمی sensor ندارد، نتیجه سبز sufficiency را ثابت نمیکند.
«Acceptance test یعنی E2E.» acceptance یک purpose/authority برای تصمیم پذیرفتن است. اگر rule مصوب را بتوان در service boundary با همان claim معتبر سنجید، الزام ذاتی برای full E2E وجود ندارد. برای ادعای UI یا deployment واقعی، البته boundary باید seamهای مربوط را شامل شود.
هر بار که shortcutی میبینی، یک probe متمایزکننده بساز: «کدام claim میخواهیم؟ کدام seam باید اجرا شود؟ authority انتظار چیست؟ چه blind spotی باقی میماند؟».
پل برای تجربههای قبلی
اگر قبلاً با test pyramid، trophy، hourglass یا دستهبندیهای مشابه کار کردهای، آنها را بهعنوان ابزار گفتوگو نگه دار، نه قانون. یک portfolio موجود را ردیفبهردیف به Risk-Based Test Strategy Record نگاشت کن. ممکن است توزیع فعلی برای سیستم تو کاملاً منطقی باشد؛ ممکن است هم فقط میراث سازمانی باشد.
برای هر test suite موجود، purpose و boundary را جدا بنویس. سپس oracle authority و risk مرتبط را پیدا کن. هر جایی که فقط «این test همیشه اینجا بوده» یا «این درصد باید حفظ شود» دلیل انتخاب است، evidence chain ناقص است. تجربه حرفهای وقتی ارزش دارد که بتوانی آن را به trace قابل بازبینی تبدیل کنی.
Fast Path از توضیحها عبور میکند، اما تمرین مستقل، mutation evidence، residual-risk disclosure و تصمیم انسانی را دور نمیزند.
بدهبستانها: چه زمانی boundary را بزرگتر کنیم؟
مرز کوچک معمولاً feedback سریعتر و localization واضحتری دارد، اما interaction کمتری را میبیند. مرز بزرگتر realism بیشتری نسبت به integration واقعی میدهد، اما هزینه setup، زمان اجرا، noise و diagnosis میتواند افزایش یابد. انتخاب باید به failure mode متصل باشد.
- اگر failure در یک invariant خالص تعریف میشود، local sensor معمولاً کافیتر و ارزانتر است.
- اگر failure از قرارداد بین domain و persistence ناشی میشود، integration لازم است چون همان seam موضوع claim است.
- اگر failure فقط در مسیر واقعی چندجزئی ظاهر میشود، broader sensor توجیه دارد.
- اگر هدف regression است، سطح را بر اساس seam defect تاریخی انتخاب کن، نه برچسب regression.
- اگر هدف acceptance است، authority مصوب را ثبت کن و boundary را فقط تا جایی ببر که claim پذیرش را واقعاً پشتیبانی کند.
Portfolio خوب لزوماً تعداد تست بیشتری ندارد؛ توضیحپذیری بیشتری دارد. reviewer باید بتواند sensor اضافی یا حذفشده را با تغییر ریسک، seam یا هزینه نگهداری توضیح دهد.
تمرین هدایتشده و مستقل
تمرین هدایتشده
یک defect احتمالی را انتخاب کن: «مقدار total در persistence با نام field اشتباه ذخیره میشود». ابتدا بدون نامگذاری سطح تست بنویس failure observable چیست. بعد seam لازم را مشخص کن: logic ذخیره + adapter contract. سپس authority را قرارداد آداپتر قرار بده و fixture کنترلشده بساز. حالا کوچکترین sensorی را انتخاب کن که همان seam را اجرا کند. در پایان بنویس این sensor چه چیزی را نمیبیند؛ مثلاً wiring مسیر API.
تمرین مستقل
فرض کن persistence پشت یک boundary جدید قرار گرفته و در عوض ریسک API wiring کمتر شده ولی ریسک timeout/contract serialization بیشتر شده است. Risk-Based Test Strategy Record را بازطراحی کن. مشخص کن کدام sensorها بدون تغییر میمانند، کدام جابهجا میشوند و کدام باید حذف یا اضافه شوند. هیچ نسبت لایهای از قبل تعیین نشده است.
Scaffold را قبل از submission کم کن: در نسخه نهایی، برای هر ردیف باید خودت risk، observed failure، boundary، oracle authority، fixture، sensor، purpose، trade-off و residual risk را پر کنی.
چه چیزی evidence قابل بازبینی محسوب میشود؟
برای این درس، ادعای «راهبرد من خوب است» evidence نیست. حداقل بسته قابل بازبینی شامل موارد زیر است:
- Risk-Based Test Strategy Record v1 با trace کامل هر ریسک تا sensor و residual risk.
- اجرای deterministic fixture محلی برای baseline.
- sensorهای مستقل که حداقل رفتار محلی، seam persistence، regression مورد تاریخی و acceptance rule را هر جا توجیه دارد میسنجند.
- mutation evidence که نشان دهد sensorها نسبت به تغییرهای هدف حساساند؛ فقط «همه تستها سبز شدند» کافی نیست.
- یک residual blind spot صریح و تصمیم درباره پذیرش، اصلاح، رد یا defer محدود.
- افشای استفاده از AI یا ابزار حمایتی. ابزار میتواند ایده تست پیشنهاد دهد، اما sufficiency نهایی را انسان باید دفاع کند.
Lab TST001-LAB1 یک سرویس کوچک محلی و بدون شبکه دارد. starter ریسکها، fixture، قاعده پذیرش و رکورد defect تاریخی را نشان میدهد، اما محل mutationها و portfolio مرجع را نشان نمیدهد. چند portfolio مختلف میتوانند معتبر باشند، به شرط اینکه شواهد و محدودیتهایشان قابل دفاع باشد.
سنجش و انتقال
S1 — retrieval: در یک سناریوی کوتاه، boundary، purpose، oracle و residual risk را از هم جدا کن. دستکم دو مفهوم را بدون overclaim بهکار ببر.
S2 — application: برای case ارائهشده بخش مرکزی Risk-Based Test Strategy Record را بساز. روایت کلی کافی نیست؛ هر conclusion باید trail قابل بازرسی داشته باشد.
S3 — diagnosis: یک portfolio ظاهراً معقول به تو داده میشود که یکی از expected valueها از خروجی فعلی برنامه گرفته شده و یکی از riskها seam مناسب ندارد. اولین promotion نامعتبر را مشخص کن و probe اصلاحیای بده که دو توضیح رقیب را از هم جدا کند.
S4 — decision: با evidence موجود یکی از چهار تصمیم ACCEPT، MODIFY، REJECT یا BOUNDED_DEFER را انتخاب کن. evidence، محدودیت و دستکم یک non-claim را صریح بنویس. تصمیم نهایی قابل واگذاری به AI نیست.
S5 — transfer: در context نزدیک اما تغییرکرده، boundary سرویس و risk profile عوض میشود. portfolio را بازطراحی کن و توضیح بده کدام sensorها جابهجا میشوند، کدام باقی میمانند و چرا. شواهد جدید بساز؛ test pathهای قبلی را صرفاً کپی نکن.
چهار بُعد بحرانی rubric عبارتاند از: technical/claim boundary، traceability evidence، human judgment همراه با محدودیت، و transfer. میانگین عددی نمیتواند شکست یک بُعد بحرانی را جبران کند.
منابع، مرز ادعا و تازگی
سه claim منبعدار/طراحیشده این درس با مرزهای زیر ثبت شدهاند:
- TST-001-R01 — FACT: مسئله test oracle یک مسئله بنیادی آزمون نرمافزار است؛ منبع دانشگاهی
DOI:10.1109/TSE.2014.2372785. بازیابی: 2026-09-02؛ بازبینی بعدی: 2027-09-02. این منبع framework یا نسبت لایه تجویز نمیکند. - TST-001-R02 — FACT: دو مطلب Google Testing درباره trade-offهای smaller/local، integration و E2E بحث میکنند:
Just Say No to More End-to-End TestsوFixing the Test Hourglass. بازیابی: 2026-09-02؛ بازبینی بعدی: 2026-12-31. هر عدد یا شکل portfolio در این context، الزام MAKNOW نیست. - TST-001-R03 — DESIGN: MAKNOW sensor را بر اساس risk، seam، oracle و decision need انتخاب میکند و fixed test-layer percentage را معیار acceptance نمیگیرد. این یک design rule درس است، نه fact جهانی.
در بررسی منابع این نسخه، هیچ source ثبتشدهای از review_due عبور نکرده است. اگر source practice-evolving به تاریخ بازبینی برسد، قبل از انتشار بعدی باید دوباره بررسی شود. عدم قطعیت اصلی همچنان باقی است: شکل بهینه portfolio به سیستم، risk، feedback economics و infrastructure وابسته است.
ارزیابی
پاسخنامهی این درس در بستهی آموزش وجود ندارد؛ خودت جواب بده و صادقانه علامت بزن. «نیاز به مرور» درس را به صف تکرار میفرستد.
TST-001-S1 retrieval
TST-001-S2 application
TST-001-S3 diagnosis
TST-001-S4 decision
TST-001-S5 transfer
ملاکهای ارزیابی (rubric)
| Critical dimension | Sufficient evidence |
|---|---|
| Claim boundary and technical correctness | Claims are no broader than evidence; no central relationship is reversed. |
| Evidence traceability | Each required conclusion traces to observable/source evidence; rejected or uncertain alternatives remain visible. |
| Human judgment and limitation disclosure | The learner makes the bounded final decision, discloses support use, and states limits/residual uncertainty. |
| Transfer | Changed-context work creates new evidence and adapts strategy rather than copying surface paths. |
All four dimensions are critical. An arithmetic average cannot compensate for failure on a critical dimension.
منابع و تازگی
مطالعهٔ موارد (case studies)
فایلهای آزمایشگاه
این fixture یک سرویس قیمتگذاری کوچک، deterministic و بدون شبکه است. change_brief.json ریسکها را نام میبرد؛ acceptance_rule.json authority پذیرش و historical_defect.json defect ثبتشده را فراهم میکنند. هیچ test-level ratio یا portfolio مرجعی در starter وجود ندارد.
python run_lab.pyرا اجرا کن تا baseline سلامت fixture را نشان دهد.strategy_record.csvرا برای riskهای مهم تکمیل کن.- testهای خود را در
tests/test_portfolio.pyبنویس. - برای هر sensor، oracle authority و residual blind spot را در رکورد ثبت کن.
- نتیجه و support/AI use را در
submission_notes.mdمستند کن.
جزئیات challengeهای پنهان تا زمان اجرا نمایش داده نمیشوند. چند portfolio میتوانند معتبر باشند؛ انتخاب boundary باید با risk و seam توجیه شود. برای چرخه mutation از MUTATION_EVIDENCE_PROTOCOL.fa-IR.md استفاده کن.