Unit Testing
Unit Testing
محتوای درس Unit Testing
.NET 10 | تست منطق مستقل و وابستگیهای کنترلشده
Unit Test رفتار یک واحد کوچک را با Dependencyهای کنترلشده بررسی میکند. هدف اصلی آن سرعت، قطعیت و پوشش Ruleهای منطق است؛ نه اجرای کامل Hosting یا Database واقعی.
این فصل با تمرکز بر قراردادهای قابل اتکا، مرزبندی مسئولیتها و رفتار قابل پیشبینی در محیط واقعی تنظیم شده است. مثالها بر پایه ASP.NET Core و .NET 10 نوشته شدهاند.
1. چارچوب موضوع و مفاهیم اصلی
Unit Test رفتار یک واحد کوچک را با Dependencyهای کنترلشده بررسی میکند. هدف اصلی آن سرعت، قطعیت و پوشش Ruleهای منطق است؛ نه اجرای کامل Hosting یا Database واقعی.
واژگان و قراردادهای این بخش باید در سراسر پروژه یکدست بمانند؛ تفاوت میان لایه HTTP، منطق برنامه و زیرساخت زمانی روشن میماند که مسئولیت هر جزء بهصورت صریح تعریف شود.
| مفهوم | کارکرد |
|---|---|
| Test Case | سناریوی قابل اجرا |
| Arrange | آمادهسازی |
| Act | اجرای رفتار |
| Assert | بررسی نتیجه |
| Fake/Mock | Dependency کنترلشده |
| Deterministic | نتیجه پایدار |
2. ساختار پیشنهادی در پروژه
Serviceهایی که Clock، Gateway یا Repository را از Interface دریافت میکنند بهسادگی قابل تست هستند. تست بر رفتار Observable متمرکز میشود، نه ترتیب Methodهای داخلی مگر زمانی که Contract باشد.
[Fact]
public async Task GetById_returns_null_when_product_does_not_exist()
{
var repository = new FakeProductRepository();
var service = new ProductService(repository);
var result = await service.GetByIdAsync(42, CancellationToken.None);
Assert.Null(result);
}3. سناریوی اجرایی
Rule کاهش موجودی با ورودیهای مرزی تست میشود: مقدار صفر، بیشتر از Stock و مقدار معتبر. Clock یا Gateway واقعی در Unit Test وارد نمیشود.
در این سناریو، قرارداد ورودی و خروجی، مسیر شکست و رفتار قابل مشاهده سرویس باید پیش از جزئیات پیادهسازی مشخص شود. این رویکرد باعث میشود تغییرات بعدی بدون وابستگی پنهان و با امکان تست دقیق انجام شوند.
[Theory]
[InlineData(10, 1, 9)]
[InlineData(10, 10, 0)]
public void DecreaseStock_updates_stock(int current, int quantity, int expected)
{
var product = new Product { Stock = current };
product.DecreaseStock(quantity);
Assert.Equal(expected, product.Stock);
}4. اصول طراحی و نگهداری
پیادهسازی قابل نگهداری تنها به درست کار کردن در مسیر موفق محدود نیست. مرزهای مسئولیت، قابلیت مشاهده، امنیت، رفتار در خطا و امکان توسعه تدریجی باید همزمان بررسی شوند.
- نام تست رفتار و شرایط را بیان کند.
- هر تست مستقل از ترتیب اجرای تستهای دیگر باشد.
- DateTime.Now و Random بدون Abstraction در منطق قابل تست محدود شوند.
- تست Implementation Detail شکننده نشود.
5. خطاهای رایج و کنترل آنها
بخش مهمی از کیفیت یک API در نحوه جلوگیری از خطاهای تکرارشونده مشخص میشود. موارد زیر باید در بازبینی کد و تستهای قبل از انتشار کنترل شوند.
- اتصال Unit Test به Database واقعی.
- یک تست بسیار بزرگ با چند سناریوی نامرتبط.
- Assert نکردن نتیجه و صرفاً نبود Exception.
- Mock کردن همه Classها حتی Value Objectهای ساده.
6. چکلیست نهایی فصل
- تستها سریع و مستقلاند.
- Ruleهای مرزی پوشش دارند.
- Dependency خارجی کنترلشده است.
- Failure تست پیام قابل فهم دارد.
7. جمعبندی
مفاهیم این فصل زمانی کامل محسوب میشوند که هم مسیر موفق و هم مسیر خطا قابل پیشبینی، قابل تست و قابل مشاهده باشند. طراحی نهایی باید با Contract API، امنیت و نیازهای نگهداری پروژه هماهنگ بماند.