مسیر C#/.NET و آداپتورهای پشته · فصل ۱ — Modern C#، ASP.NET Core، EF Core و Testing · 328
.NET Testing, Diagnostics و Hosting
دانش قدیمی یا پراکندهی .NET دارد اما آن را با الگوهای مدرن API/data/testing/hosting همگام نکرده است. موضوع جاری: «.NET Testing, Diagnostics و Hosting». میتواند «.NET Testing, Diagnostics و Hosting» را در یک سرویس .NET محدود اجرا و با تست/diagnostics مناسب verify کند.
خلاصهٔ درس
دانش قدیمی یا پراکندهی .NET دارد اما آن را با الگوهای مدرن API/data/testing/hosting همگام نکرده است. موضوع جاری: «.NET Testing, Diagnostics و Hosting».
میتواند «.NET Testing, Diagnostics و Hosting» را در یک سرویس .NET محدود اجرا و با تست/diagnostics مناسب verify کند.
خروجی این درس
میتواند «.NET Testing, Diagnostics و Hosting» را در یک سرویس .NET محدود اجرا و با تست/diagnostics مناسب verify کند.
تستها سبزند؛ پس چرا سرویس در محیط جدید بالا نمیآید؟
سرویس کوچکی دارید که پاسخ یک وابستگی را برمیگرداند. آزمونهای واحد موفقاند. روی رایانهٔ شما هم اجرا میشود، اما در محیط جدید نام سرویس تنظیم نشده و شروع برنامه شکست میخورد. دفعهٔ بعد تنظیم را اصلاح میکنید؛ اینبار وابستگی کند میشود و کاربر پاسخ خطا میگیرد. در لاگ فقط «timeout» میبینید و معلوم نیست کدام درخواست و کدام عملیات به آن مربوط بودهاند.
در این درس یک بستهٔ شواهد تست، مشاهدهپذیری و آمادگی میزبانی سرویس .NET میسازید: .NET Service Verification, Observability and Hosting Readiness Pack v1. پرسش اصلی آن روشن است: برای همین نسخه، همین تنظیمات و همین محیط، چه رفتاری را واقعاً بررسی کردهایم و چه چیزی هنوز اثبات نشده است؟
حدود ۶۰ دقیقه فعالیت در نظر بگیرید: ۱۰ دقیقه برای مدل و مرز تست، ۱۵ دقیقه برای مثال و کد، ۱۵ دقیقه برای تمرین هدایتشده، ۱۵ دقیقه برای مسئلهٔ مستقل و ۵ دقیقه برای دفاع از نتیجه. نصب SDK و اجرای تکمیلی پروژهٔ .NET زمان جداگانه میخواهد.
تمرین اصلی با Python و دادههای مصنوعی اجرا میشود. دادههای آن گزارش اجرای واقعی .NET نیستند. پروژهٔ C# و آزمونهای یکپارچه نیز در بسته وجود دارند، اما اجرای آنها توسط تهیهکننده در این نسخه UNVERIFIED است. موفقیت تمرین، توانایی ارزیابی شواهد را نشان میدهد؛ موفقیت اجرای سرویس باید با خروجی همان اجرا ثبت شود.
این درس برای کسی است که C# و ساختار اولیهٔ یک API در ASP.NET Core را میشناسد و میخواهد از «روی سیستم من کار میکند» به یک تصمیم قابلدفاع دربارهٔ میزبانی برسد.
ساخت migration پایگاه داده، نصب Kubernetes یا Kafka، انتخاب سرویس ابری و انتشار روی محیط زنده در محدودهٔ این تمرین نیست.
از چه نقطهای وارد شوید؟
پیشنیاز ضروری، مبانی مسیر .NET است. آشنایی با دسترسی داده و migration کمک میکند، اما تمرین حاضر پایگاه داده ندارد.
پیش از ادامه توضیح دهید: یک درخواست HTTP چطور از مسیر برنامه به handler میرسد؟ تزریق وابستگی یا DI چه چیزی را برای handler فراهم میکند؟ آیا اجرای یک متد بهتنهایی همان مسیر را طی میکند؟
اگر پاسخ دشوار است، این پل کوتاه را بخوانید: host منابع اجرای برنامه را کنار هم قرار میدهد؛ مسیر درخواست، ورودی HTTP را به عملیات وصل میکند؛ DI نمونهٔ وابستگی موردنیاز را میسازد. فراخوانی مستقیم متد میتواند منطق همان متد را بررسی کند، ولی وجود route، اتصال تنظیمات و ساختهشدن وابستگی را خودبهخود بررسی نمیکند. برای آمادگی ورود، یک خطای ممکن در هر یک از این سه بخش نام ببرید.
اگر تازه وارد این موضوع شدهاید، جدول مثال را ستونبهستون بخوانید. اگر برای رفع خطا آمدهاید، نخستین شاهد نامعتبر را پیدا کنید و فقط همان بخش را تعمیر کنید. اگر تجربه دارید، مستقیماً به تمرین مستقل بروید؛ باید همان معیارهای شواهد و همان مسئلهٔ انتقال را پاس کنید.
آمادگی میزبانی یک زنجیرهٔ شواهد است
آزمون واحد، رفتار بخش محدودی از کد را جداگانه بررسی میکند. آزمون یکپارچه بررسی میکند اجزا در کنار هم چگونه رفتار میکنند. در ASP.NET Core، WebApplicationFactory<Program> میتواند برنامهٔ تحت آزمون، یا SUT، را با میزبان آزمایشی راهاندازی کند و درخواست را از مسیر HTTP برنامه بفرستد. راهنمای آزمون یکپارچه
در نمونهٔ این درس، وابستگی بیرونی با یک نمونهٔ مصنوعی جایگزین میشود. بنابراین route، DI، تنظیمات و پاسخ برنامه در مرز آزموناند؛ شبکهٔ واقعی وابستگی، TLS، پراکسی و میزبان مقصد بیرون آناند. نوشتن واژهٔ «integration» در نام تست این مرز را بزرگتر نمیکند.
نمودار همراه درس سه خروجی دارد: شواهد کامل به آمادگی محدود میرسند؛ شاهد منفی به تعمیر و اجرای دوباره میرسد؛ شاهد مفقود به HOLD میرسد. توضیح متنی آن چنین است: ابتدا هویت نسخه و محیط، سپس تستهای بحرانی، تنظیمات و عمر وابستگیها، بعد شروع و توقف، و در پایان شواهد خطای تزریقشده را بررسی کنید. هیچ مسیر میانبری از «تست واحد موفق» به نتیجهٔ نهایی وجود ندارد.
این دروازهٔ آمادگی، قاعدهٔ طراحی MAKNOW برای تمرین است؛ Microsoft چنین گواهیای برای این سرویس صادر نکرده است. HOSTING_READY در دادهٔ مصنوعی فقط یعنی قواعد همین fixture برقرارند.
واژهها را به شاهد قابلدیدن تبدیل کنید
| پرسش | شاهد لازم | چیزی که جای آن را نمیگیرد |
|---|---|---|
| چه چیزی تست شده؟ | شناسهٔ تست، سطح، SUT، وضعیت ورودی و انتظار/مشاهده | تعداد کل تستهای سبز |
| تنظیم از کجا آمده؟ | نام محیط، نام کلید و منبع تنظیم | تصویر اجرای قبلی |
| چه زمانی نمونه ساخته میشود؟ | عمر وابستگی و نتیجهٔ بررسی scope | ثبت یک نوع در DI |
| چرخهٔ اجرا درست است؟ | شروع، health و توقف با شناسهٔ ثبت | فقط خروجی شروع |
| خطای خاص قابلپیگیری است؟ | لاگ و trace مرتبط، سنجه و ثبت تشخیصی | جملهٔ عمومی «خطا رخ داد» |
| تصمیم به چه چیزی متصل است؟ | نسخه، محیط، شناسهٔ اجرا، هش ورودی و مسئول بازبینی | کپی نتیجهٔ محیط قبلی |
UNKNOWN یعنی داده را نمیدانیم؛ UNVERIFIED یعنی بررسی لازم اجرا یا ثبت نشده؛ STALE یعنی شاهد به زمان یا زمینهٔ فعلی تعلق ندارد؛ FAILED یعنی مشاهده با انتظار معتبر ناسازگار است. REVIEW_REQUIRED نیاز به بازبینی را ثبت میکند. نتیجهٔ کلی در هرکدام از این حالتها HOLD است. SECRET_EXPOSURE_RISK علت مشخصی است که به HOLD منجر میشود و با موفقیت تستهای دیگر خنثی نمیشود.
منبع تنظیم مهم است. در نگاشت متغیرهای محیطی ASP.NET Core، Service__Name به کلید سلسلهمراتبی Service:Name مربوط میشود. در تمرین، Service:Name و Dependency:TimeoutMs ضروریاند. مقدارهای ۱۰۰، ۲۰ و ۲۵۰ میلیثانیه که بعداً میبینید، انتخابهای آموزشی همین fixture هستند. تنظیمات ASP.NET Core
از تنظیم معتبر تا خطای قابلپیگیری
Generic Host تنظیمات، DI، logging و چرخهٔ سرویسهای میزبانیشده را کنار هم مدیریت میکند. داشتن host، بهتنهایی شاهد درستبودن تنظیمات نیست. Generic Host
در پروژهٔ همراه، تنظیمات وابستگی به یک کلاس options متصل میشوند. اعتبارسنجی هنگام شروع، فقدان نام سرویس یا timeout نامعتبر را آشکار میکند:
builder.Services.AddOptions<ServiceOptions>()
.BindConfiguration("Service")
.Validate(o => !string.IsNullOrWhiteSpace(o.Name), "Service name required")
.ValidateOnStart();
ValidateOnStart زمان اعتبارسنجی را به شروع برنامه میآورد. پیام خطا باید نام قاعده را توضیح دهد؛ لازم نیست مقدار تنظیم یا تمام پیکربندی را چاپ کند. در تست، تنظیم آزمایشی را پیش از مصرف options در اختیار host قرار دهید. الگوی options
عمر Scoped معمولاً یک نمونه در scope درخواست میدهد؛ Singleton یک نمونهٔ مشترک دارد. در مثال، وابستگی مصنوعی scoped و ابزارهای telemetry مشترکاند. گرفتن مستقیم یک وابستگی scoped در singleton مرز عمر را مخدوش میکند؛ بررسی scope را در host تست فعال میکنیم. این انتخاب برای نمونه است و نسخهٔ عمومی طراحی همهٔ سرویسها نیست. عمر وابستگیها
سه نوع شاهد تشخیصی را جدا بخوانید: لاگ رخداد مشخص را شرح میدهد؛ سنجه تعداد یا اندازهگیری تجمیعی را نشان میدهد؛ trace مسیر عملیات مربوط به یک درخواست را پیوند میدهد. APIهای مورد استفاده در .NET شامل ILogger، Meter و ActivitySource/Activity هستند. داشتن این ابزارها در کد، ثبت یا صدور موفق داده را اثبات نمیکند. تشخیص خطا در .NET، مشاهدهپذیری با OpenTelemetry
در خطای تزریقشدهٔ ما، لاگ رخداد 1002 باید شناسهٔ trace همان عملیات را داشته باشد. سنجهٔ lesson.dependency.timeouts یک واحد زیاد میشود و فقط برچسب کمتنوع operation=dependency دارد. شناسهٔ هر درخواست را به برچسب سنجه تبدیل نمیکنیم؛ پیوند درخواست در لاگ و trace ثبت میشود. collector ابری در این نمونه تنظیم نشده؛ تست، داده را با listener و logger آزمایشی در حافظه دریافت میکند.
برای health نیز دو سؤال متفاوت تعریف کردهایم: آیا فرایند پاسخ میدهد؟ آیا وابستگی موردنیاز آماده است؟ قرارداد نمونه برای حالت عادی readiness برابر ۲۰۰، برای خرابی وابستگی readiness برابر ۵۰۳ و برای liveness در همان خرابی برابر ۲۰۰ است. این کدها و معنای مسیرها قرارداد خود نمونهاند؛ موفقیت آنها رفتار load balancer واقعی را ثابت نمیکند.
توقف را جدا ثبت کنید: درخواست توقف، دریافت علامت توقف و پایان host باید شاهد داشته باشند. callback توقف، شاهد تخلیهٔ تمام درخواستهای در حال اجرا نیست. برای آن ادعا باید درخواست طولانی، زمانسنج و رفتار میزبان مقصد هم آزمایش شوند.
کد تست را به سه پرسش تقسیم کنید
در ServiceTests.cs این بخش از آزمون درخواست عادی را میبینید؛ ServiceFactory همان کلاس تنظیم میزبان آزمایشی در فایل همراه است:
using var factory = new ServiceFactory();
using var client = factory.CreateClient();
using var response = await client.GetAsync("/sample");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
using var payload = JsonDocument.Parse(
await response.Content.ReadAsStringAsync());
Assert.Equal("synthetic-ok",
payload.RootElement.GetProperty("value").GetString());
آمادهسازی کجاست؟ factory محیط Testing و تنظیمات در حافظه را فراهم میکند. عمل مورد آزمایش چیست؟ درخواست GET /sample از مسیر برنامه عبور میکند؛ فراخوانی مستقیم ReadAsync نیست. چه چیزی سنجیده میشود؟ هم کد پاسخ و هم مقدار بدنه باید با انتظار برابر باشند. اگر مسیر را اشتباه بنویسید، یا پاسخ ۲۰۰ با بدنهٔ نامرتبط برگردد، یکی از این دو بررسی باید اختلاف را آشکار کند. اینها انتظار از کد آزموناند؛ رسید اجرای واقعی در این نسخه نداریم.
در آزمون تنظیم نامعتبر، انتظار اصلاً «یک پاسخ HTTP خطا» نیست. CreateClient باعث راهاندازی میزبان میشود و اعتبارسنجی options باید همانجا شروع را رد کند. صرف رخدادن هر exception کافی نیست: کد آزمون بررسی میکند علت، OptionsValidationException باشد. خطای پیدا نشدن فایل یا نصب ناقص SDK نباید بهجای موفقیت آزمون تنظیم حساب شود. نام تست، ورودی آزمایش و نوع شکست موردانتظار را به همین دلیل جدا ثبت میکنیم.
در timeout چه اتفاقی را دنبال میکنید؟
handler یک مهلت برای خواندن وابستگی میسازد و cancellation درخواست را نیز به آن متصل میکند. در حالت آموزشیِ خطای تزریقشده، تأخیر ۲۵۰ میلیثانیه از مهلت ۱۰۰ میلیثانیه بیشتر است. مسیر catch برای لغو ناشی از این مهلت، span را خطادار علامت میزند، شمارنده را افزایش میدهد، رخداد 1002 را ثبت میکند و پاسخ 504 میدهد. اگر خود درخواست لغو شده باشد، شرط catch اجازه نمیدهد آن را بیدلیل timeout وابستگی بنامیم.
ترتیب خواندن شواهد را حفظ کنید: نخست ورودیِ ایجادکنندهٔ خطا، سپس پاسخ، بعد span و لاگ همان عملیات و در پایان تغییر سنجه. یک شمارندهٔ تجمیعی بهتنهایی نمیگوید کدام درخواست خطا داده است. از آن طرف، برابری چند شناسه نیز بدون شاهد ثبتشده، اصل اجرای خطا را اثبات نمیکند. در تمرین، این دادهها عمداً مصنوعیاند و فقط منطق تصمیمگیری را میآزمایند.
مسیر /ready در کد همراه فقط پرچم مصنوعی Dependency:Available را میخواند؛ هیچ درخواست واقعی به وابستگی نمیفرستد. بنابراین این نمونه معنای دو مسیر health را آموزش میدهد. برای ادعای تشخیص قطعی سلامت وابستگی واقعی، به بررسی مناسب همان وابستگی و ثبت رفتار در محیط مقصد نیاز دارید.
مثال حلشده: یک timeout موردانتظار میتواند تست موفق داشته باشد
فایل fixtures/baseline.json شواهد ساختگی محیط Testing و زمینهٔ local-r1 را دارد. timeout برابر ۱۰۰، تأخیر عادی ۲۰ و تأخیر تزریقشده ۲۵۰ میلیثانیه است. قبل از محاسبهٔ نتیجه، انتظارها را بخوانید:
| بررسی | انتظار | مشاهدهٔ مصنوعی | تفسیر |
|---|---|---|---|
| درخواست عادی | HTTP 200 | HTTP 200 | این مسیر انتظار را برآورده کرده |
| timeout تزریقشده | HTTP 504 | HTTP 504 | مدیریت خطا با انتظار برابر است |
| حذف تنظیم ضروری | رد شروع | رد شروع | جلوگیری از شروع نامعتبر بررسی شده |
| چرخهٔ عادی | شروع و توقف ثبتشده | هر دو PASS | فقط همین چرخه پوشش دارد |
| مشاهدهٔ timeout | لاگ و trace همشناسه، سنجه +1 | حاضر | این خطای مصنوعی قابلپیگیری است |
اول هویت همهٔ captureها را با local-r1 تطبیق میدهیم. بعد حضور تنظیمات، سه تست بحرانی، health و توقف را بررسی میکنیم. در پایان مقدار ممنوع را در ثبت تشخیصی جستوجو میکنیم. هیچ مانع تعریفشدهای باقی نمانده؛ نتیجهٔ نمونه HOSTING_READY با دامنهٔ SYNTHETIC_ONLY است. این جمله به سرویس اجراشده یا استقرار واقعی تعمیم پیدا نمیکند.
چرا خطای ۵۰۴ تست را قرمز نکرد؟ چون رفتار موردانتظارِ آزمون خطا همین پاسخ کنترلشده بود. اگر درخواست عادی ۵۰۴ بگیرد، نتیجه متفاوت است. لاگ timeout هم بهتنهایی موفقیت یا شکست آزمون را تعیین نمیکند؛ انتظار، مشاهده و وضعیت ورودی باید کنار هم باشند.
اکنون فقط Service:Name را حذف کنید. حتی اگر سطر startup_state=PASS دستنخورده بماند، ورودی جدید شرط شروع را ندارد. تصمیم قبلی دیگر قابلاستفاده نیست: علت CONFIG_MISSING با وضعیت FAILED و نتیجهٔ کلی HOLD ثبت میشود. تعمیر، تأمین تنظیم از منبع درست و اجرای دوبارهٔ شروع است؛ تغییر دستی PASS شاهد تازه تولید نمیکند. در CSV کامل، ستونهای چرخهٔ اجرا و telemetry شواهد مشترک بستهاند و کنار سطرهای تست تکرار میشوند. شروع و توقف عادی، متعلق به سناریوی NORMAL است؛ سطر missing_config یک تلاش جداگانه برای شروع نامعتبر را بررسی میکند. تکرار ستونها به معنی شروع موفق همان سناریوی نامعتبر یا داشتن trace مستقل برای هر تست نیست.
از مشاهدهٔ خام به یک علت قابلدفاع برسید
قبل از نوشتن نتیجه، دو مقدار تعیینکننده را خودتان از فایل بخوانید. در پوشهٔ learner، این فرمان فقط مشاهده را چاپ میکند و هیچ تصمیمی نمیسازد:
python -c 'import json; x=json.load(open("fixtures/missing_env.json")); print(x["configuration"]["values"].get("Service:Name")); print(x["lifecycle"]["startup_state"])'
خروجی این فایل None و سپس PASS است. این اختلاف را چنین توضیح دهید: مقدار فعلی شرط ضروری را ندارد، اما برچسب شروع از دادهٔ قبلی باقی مانده است. نام قاعده در policy.json برابر CONFIG_MISSING است. پس در بخش تصمیم پاسخ خود بنویسید:
{
"readiness_state": "HOLD",
"issues": [{"code": "CONFIG_MISSING", "state": "FAILED"}],
"evidence_refs": ["/configuration/values", "/lifecycle/startup_state"]
}
این قطعه فقط بخش تصمیم است؛ فایل تحویل کامل باید هویت، هش ورودی و قواعد، تاریخ ارزیابی و سه توضیح را هم داشته باشد. برای rationale اختلاف بالا را شرح دهید؛ برای minimal_repair تأمین تنظیم از منبع درست و ثبت دوبارهٔ شروع را بنویسید؛ برای review_trigger تغییر تنظیم یا محیط را ذکر کنید. نوشتن «درست شد» کافی نیست، چون هنوز اقدام و شاهد تازه را نشان نمیدهد. این الگوی هدایتشده را به پاسخ آمادهٔ مسئلهٔ انتقال تبدیل نکنید؛ آن مسئله چند بُعد متفاوت دارد.
تاریخ هم بخشی از شاهد است. اگر همان baseline را پس از ۱۸ اکتبر ۲۰۲۶ ارزیابی کنید، اعتبار بازبینی نسخه گذشته است. دادهٔ قدیمی با ثابتماندن تستها تازه نمیشود. برای بازسازی مثال تاریخی، تاریخ ۱۲ سپتامبر را صریح ثبت کنید؛ برای تصمیم امروز، تاریخ واقعی ارزیابی را ثبت کنید.
پنج میانبری که اطمینان کاذب میسازند
| میانبر | شاهد تعیینکننده | اقدام لازم |
|---|---|---|
| تنظیم حذف شده، ولی شروع هنوز سبز است | مقدار فعلی کلید ضروری | تعمیر تنظیم و ثبت شروع تازه |
| لاگ timeout داریم، ولی به trace وصل نیست | برابری شناسههای همان اجرا | اصلاح همبستگی و تکرار خطا |
| تست route را با متد دارای mock عوض میکنیم | سطح تست و حضور میزبان آزمایشی | بازگرداندن درخواست از مسیر برنامه |
| برای عیبیابی token را چاپ میکنیم | محتوای واقعی ثبت تشخیصی | حذف دادهٔ ممنوع و تکرار بررسی |
| رسید توقف نداریم، اما سرویس را آماده مینامیم | ثبت پایان چرخه | نگهداشتن UNVERIFIED تا ثبت شاهد |
یک اختلاف شناسه را با نسبتدادن دستی لاگ به trace حل نکنید. علت ممکن است انتقال نادرست context، تنظیم listener یا capture متعلق به اجرای دیگر باشد. ابتدا علت را جدا کنید و سپس خطا را دوباره بسازید.
در فایل افشای داده فقط یک canary ساختگی وجود دارد؛ credential واقعی نیست. پیدا نشدن همین رشته، همهٔ نشتهای ممکن را رد نمیکند. بررسی نام فیلدهای ممنوع و بازبینی دامنهٔ داده نیز لازماند. در محیط واقعی، dump حافظه یا exception کامل میتواند دادهٔ حساس داشته باشد؛ دامنهٔ جمعآوری باید پیش از capture تعیین شود. حذف نام یک تست ضروری از فهرست، یا تغییر همزمان انتظار و مشاهده از ۲۰۰ به ۵۰۴، شکست را تعمیر نمیکند. قرارداد ثابتِ قابلدیدن در policy.json سه تست ضروری و انتظارشان را مشخص کرده است. اگر ساختار تعیینکنندهٔ ورودی خراب یا قرارداد آن دستکاری شده باشد، نتیجه با علت INPUT_INVALID، وضعیت UNKNOWN و تصمیم کلی HOLD ثبت میشود. ابتدا دادهٔ قابلبررسی را فراهم کنید.
اگر تجربه دارید، مرز ادعای خود را دقیقتر کنید
به این پیشنهاد پاسخ دهید: «وابستگی واقعی را حذف کنیم و تمام تستها را با fake اجرا کنیم تا سریعتر شوند.» برای بررسی route و خطای کنترلشده، این fixture مفید است. برای قرارداد واقعی وابستگی، تأخیر شبکه و رفتار محیط مقصد، کافی نیست. پاسخ قابلدفاع باید هم پوشش بهدستآمده و هم پوشش باقیمانده را نام ببرد.
سپس بگویید چه چیزی پذیرش را متوقف میکند: تغییر نسخهٔ SUT، منبع تنظیم، انتظار پاسخ، مسیر صدور telemetry یا پروفایل میزبانی باید شاهد مربوط را باطل کند و بازبینی تازه بخواهد. تعداد تستها نمیتواند این اختلاف زمینه را جبران کند.
کدام بررسی را کجا انجام دهید؟
| ابزار یا روش | کاربرد مناسب در این درس | محدودیت |
|---|---|---|
| تست واحد | منطق محدود و حالتهای ورودی متعدد | route و host را اجرا نمیکند |
| WebApplicationFactory و fake | مسیر درخواست، تنظیمات، DI و خطای کنترلشده | رفتار واقعی وابستگی را نشان نمیدهد |
| آزمون فرایند محلی | شروع/توقف فرایند و متغیرهای محیطی | میزبان مقصد میتواند متفاوت باشد |
| اجرای محیط دورریختنی مقصد | قرارداد همان پروفایل میزبانی | هزینه و زمان بیشتر؛ نیازمند ثبت زمینه |
| لاگ، سنجه و trace | توضیح رفتار مشاهدهشده | جای assertion و انتظار مشخص را نمیگیرند |
برای خطای فقدان تنظیم، ابتدا کوچکترین تست شروع را اجرا کنید. برای timeout، اول مسیر HTTP با وابستگی کنترلشده را بررسی کنید. افزایش بیهدف حجم لاگ میتواند هزینه و دادهٔ اضافی تولید کند؛ ثبتِ کم اما مرتبط باید سؤال تشخیصی را پاسخ دهد.
تمرین: تصمیم را خودتان بسازید
از بستهٔ تمرین استفاده کنید. Python 3.10 یا بالاتر و کتابخانهٔ استاندارد کافی است؛ دادهٔ ابری یا حساب کاربری لازم نیست. در پوشهٔ learner:
python run_checks.py --inventory
python run_checks.py --template fixtures/missing_env.json submission.json
python run_checks.py --check fixtures/missing_env.json submission.json
فرمان دوم هویت و هش ورودی را وارد میکند و تصمیم را خالی میگذارد. policy.json معیارها را نشان میدهد. در submission.json نتیجه، علتها با code و state، ارجاعهای JSON Pointer، توضیح، تعمیر حداقلی و محرک بازبینی را بنویسید. مثال ارجاع: /configuration/values. هیچ مقدار محرمانهای را در توضیح کپی نکنید.
ابتدا missing_env را با کمک مثال حل کنید. سپس uncorrelated_timeout، mocked_unit، secret_exposure و missing_shutdown را بدون نتیجهٔ آماده تحلیل کنید. بررسی عمومی فقط ساختار، اتصال به ورودی و سازگاری پایهٔ پاسخ را میسنجد؛ پیام موفقیت آن بهتنهایی درستی تصمیم را ثابت نمیکند. ارزیابی معنایی جداگانه لازم است.
برای کار مستقل، transfer_changed.json را باز کنید. محیط به Staging، پروفایل به container دورریختنی و تأخیر عادی به ۱۸۰ میلیثانیه تغییر کرده؛ نام سرویس در منبع جدید وجود ندارد و captureهای قبلی هنوز local-r1 هستند. بدون کپی نتیجهٔ baseline، تمام علتهای توقف را پیدا کنید. فقط اضافهکردن نام سرویس مسئلهٔ کندی و شواهد قدیمی را حل نمیکند.
برای اجرای تکمیلی و اختیاری، دستورهای dotnet/README.fa.md را دنبال کنید. این اجرا جزء شرط تحویل تمرین اصلی Python نیست؛ هر ادعای اجرای واقعیِ سرویس به رسید خودش نیاز دارد. تستهای آن پاسخ عادی، timeout، رد شروع نامعتبر، telemetry، health و توقف را هدف میگیرند. پس از اجرای واقعی، نسخهٔ SDK، نتایج TRX و captureهای تازه را ثبت کنید. فایلهای مصنوعی را به گزارش واقعی تغییرنام ندهید. برای بازسازی مثالِ ثابت با تاریخ مشخص، به فرمان ساخت قالب --as-of 2026-09-12 اضافه کنید. بدون این گزینه، تاریخ امروز در evaluated_on ثبت میشود. قالب علاوه بر هش fixture، policy_sha256 را نیز ثبت میکند؛ پاسخ متعلق به قواعد قدیمی نباید بیصدا با قواعد تازه ارزیابی شود.
فایل evidence_field_map.csv محل هر یک از ۲۱ بُعد شواهد را نشان میدهد. برای هر تست بحرانی سطر متناظر را بخوانید؛ برای چرخهٔ اجرا و telemetry به شواهد مشترک بسته رجوع کنید. جای نتیجه در submission است و عمداً در fixture پر نشده است.
در مسئلهٔ انتقال، بین «پیشنهاد تعمیر» و «مشاهدهٔ تعمیرشده» فاصله بگذارید. میتوانید منبع تنظیم درست یا مهلت متفاوتی را پیشنهاد دهید، اما افزایش مهلت ممکن است انتظار پاسخ و رفتار خطای تزریقشده را هم تغییر دهد. اجرای دوبارهٔ تستهای مرتبط و ثبت زمینهٔ تازه لازم است. تعویض دستی context_id در دادهٔ قدیمی، اجرای تازه نیست. اگر صرفاً یک فرض آموزشی را شبیهسازی میکنید، روی کپی کار کنید و مصنوعیبودن آن را نگه دارید.
تحویل قابلبازبینی چه دارد؟
هر تصمیم باید شناسه و هش fixture، زمینهٔ اجرا، دامنهٔ SYNTHETIC_ONLY، علتهای کامل و ارجاع به فیلدهای تعیینکننده را داشته باشد. در تصمیم توقف، تعمیر حداقلی و شرط بازبینی بعدی را هم بنویسید. هش ثابت میکند پاسخ به کدام بایتهای ورودی وصل شده؛ صحت آن دادهها را ثابت نمیکند.
جدول کامل شواهد در فایل CSV همراه قرار دارد: تست و سطح، SUT و میزبان آزمایشی، وضعیت fixture، محیط و منبع تنظیم، مرز دادهٔ محرمانه، عمر وابستگی، شروع/توقف/health، لاگ/سنجه/trace و همبستگی، نوع خطا و capture، پروفایل، نتیجه و مسئول بازبینی. مقدار نامعلوم را صریح ثبت کنید.
برای اجرای واقعی یک پروندهٔ جدا بسازید: زمان اجرا، revision کد، نسخهٔ SDK/runtime، فرمان دقیق، کد خروج، تعداد و نام تستها، وضعیت انتظار و مشاهده، و ثبتهای تشخیصی پالایششده. نبود SDK یا شکست restore برابر UNVERIFIED است، نه PASS. عبور از تست در حافظه نیز مجوز انتشار زنده نیست. در بستهٔ تمرین، پوشهٔ resources را باز کنید: NET-004-T1.csv جدول کامل، rubric.md معیارهای ارزیابی و source_links.md منابع آموزشی و نسخههای وابستگی را دارد.
ارزیابی و انتقال یادگیری
- مرز آزمون واحد و آزمون مسیر HTTP را با همین سرویس توضیح دهید و یک رفتار بیرون مرز تست در حافظه نام ببرید.
- برای baseline یک بستهٔ شواهد کامل بسازید و توضیح دهید چرا ۵۰۴ در آزمون تزریق خطا میتواند انتظار درست باشد.
- در مثال حذف تنظیم، کدام فیلد ادعای شروع موفق را باطل میکند؟ پیامد، وضعیت و تعمیر حداقلی را ثبت کنید.
- برای
transfer_changedتصمیم تازه بسازید. مشخص کنید کدام تنظیم، انتظار پاسخ و capture باید دوباره بررسی شود. یک پاسخ که فقط نتیجهٔ baseline را کپی کند کافی نیست.
پذیرش آموزشی به پنج معیار وابسته است: مرز درست، اتصال دقیق شواهد، درنظرگرفتن همهٔ شواهد منفی و علتهای توقف، تصمیم متناسب با داده و حل مستقل زمینهٔ جدید. یک نمرهٔ میانگین خوب، افشای داده یا ادعای موفقیت بیشاهد را جبران نمیکند. جزئیات معیارها در rubric همراه است.
AI میتواند دادهها را مرتب و مقایسه کند؛ مجاز نیست نتیجهٔ تست، capture، اجازهٔ مسئول یا اجرای میزبان را بسازد. شما باید بتوانید تصمیم را بدون تکیه بر استدلال پنهان یک ابزار توضیح دهید. پس از این درس، Kubernetes و Kafka مسئلهٔ متفاوت انتخاب فناوری را بررسی میکند.
منابع و زمان بازبینی
مبنای APIهای درس، مستندات .NET/ASP.NET Core 10 است. منابع اصلی Microsoft دربارهٔ آزمون یکپارچه، diagnostics، OpenTelemetry و Generic Host در ۱۲ سپتامبر ۲۰۲۶ بازبینی شدند. جزئیات options، DI و configuration از صفحات رسمی پیوندشده در متن آمدهاند.
موعد بازبینی بعدی ۱۸ اکتبر ۲۰۲۶ است؛ تغییر معنادار API، نسخهٔ هدف یا قواعد محیط، بازبینی زودتر میخواهد. آستانههای timeout، کدهای تصمیم، فیلدهای ممنوع و قواعد پذیرش از طراحی همین تمریناند. توضیح سازوکار یک API را با تأیید آمادگی سرویس اشتباه نگیرید.
ارزیابی
پاسخنامهی این درس در بستهی آموزش وجود ندارد؛ خودت جواب بده و صادقانه علامت بزن. «نیاز به مرور» درس را به صف تکرار میفرستد.
ملاکهای ارزیابی (rubric)
هر ردیف باید کافی باشد؛ نمرهٔ میانگین جای شرط بحرانی را نمیگیرد. / Every dimension must be sufficient; an average cannot override a critical failure.
| معیار / Dimension | کافی / Sufficient | ناکافی / Insufficient |
|---|---|---|
| مرز / Scope | تفکیک unit، pipeline، host و وابستگی واقعی / Distinguishes unit, pipeline, host and real dependency | تست در حافظه را deployment مینامد / Claims deployment from an in-memory test |
| اتصال شواهد / Binding | شناسه، هش ورودی و قواعد، تاریخ ارزیابی، محیط و ارجاع دقیق / Exact identity, input and policy digests, evaluation date, environment and field references | نتیجهٔ قدیمی یا ارجاع نامعتبر / Copied result or invalid reference |
| شاهد منفی / Negative evidence | تمام علتهای توقف و نوع وضعیت / Complete blockers and typed states | افشا یا فقدان داده را نادیده میگیرد / Ignores exposure or missing data |
| تصمیم / Decision | دامنهٔ مصنوعی، تعمیر و محرک بازبینی / Synthetic scope, repair and review trigger | موفقیت بیشاهد / Unsupported success |
| انتقال / Transfer | محاسبهٔ دوبارهٔ تنظیم، تأخیر و زمینه / Rechecks settings, latency and context | کپی baseline یا تعمیر فقط یک علت / Copies baseline or repairs only one cause |
قبولی بخش Python اثبات اجرای C# نیست. / Passing Python does not prove C# execution. بازبین باید بتواند استدلال را از فایلهای قابلدیدن بازسازی کند. / A reviewer must reconstruct the reasoning from visible files.
منابع و تازگی
مطالعهٔ موارد (case studies)
فایلهای آزمایشگاه
نیاز: Python 3.10 یا بالاتر؛ بدون کتابخانهٔ بیرونی. همهٔ ورودیها مصنوعیاند.
python run_checks.py --inventoryرا اجرا کنید.- قواعد
policy.jsonو درس فارسی را بخوانید. python run_checks.py --template fixtures/missing_env.json submission.jsonرا اجرا کنید.- تصمیم، علتها، ارجاعها و استدلال خود را در فایل خروجی بنویسید.
python run_checks.py --check fixtures/missing_env.json submission.jsonرا اجرا کنید.
نتیجهٔ STRUCTURE_PASS_SEMANTICS_UNREVIEWED فقط کنترل ساختاری است. برای درستی تصمیم، ارزیابی معنایی و دفاع از شواهد لازم است. ابزار پاسخ نهایی را پر نمیکند. فایل خروجی موجود بازنویسی نمیشود.
پس از مثال هدایتشده، همهٔ حالتهای منفی و transfer_changed را بررسی کنید. stale_review و failed_request تمرین تکمیلیاند. فایلهای ورودی را تغییر ندهید؛ تعمیر پیشنهادی را در پاسخ شرح دهید. برای آزمایش یک تغییر دلخواه نسخهای جدا بسازید و آن را شاهد اجرای واقعی ننامید.
dotnet/README.fa.md اجرای تکمیلی C# را توضیح میدهد. موفقیت Python هیچ تست C# یا میزبانی واقعی را اثبات نمیکند.
قالب، تاریخ ارزیابی و هش قواعد را ثبت میکند. برای مثال تاریخی از --as-of 2026-09-12 همراه --template استفاده کنید؛ حالت پیشفرض تاریخ امروز است. evidence_field_map.csv محل ۲۱ بُعد شواهد را نشان میدهد. قرارداد ثابت policy قابل حذف نیست؛ ورودی خراب باید UNKNOWN/HOLD بماند.
منابع همراه: CSV, rubric, source links.