آموزش Unit Test در سی شارپ

تاریخ: 1404/12/4 ساعت: 12:16 بازدید: 8

Unit Test در سی شارپ چیست و چرا اینقدر مهم است؟

اگر یه برنامه‌نویس سی شارپ هستی و هنوز تست‌نویسی رو جدی نگرفتی، باید صادقانه بگم که داری یکی از مهم‌ترین مهارت‌های دنیای امروز توسعه نرم‌افزار رو نادیده می‌گیری. Unit Test یا تست واحد یعنی نوشتن کدی که کد دیگه‌ات رو تست می‌کنه. ساده به نظر می‌رسه، ولی تأثیرش روی کیفیت، نگهداری و اطمینان از کد شما فوق‌العاده‌ست.

تصور کن یه پروژه بزرگ داری و یه تغییر کوچیک توی یه کلاس می‌دی. چطور مطمئن می‌شی که بقیه قسمت‌های برنامه خراب نشدن؟ اینجاست که Unit Test مثل یه شبکه ایمنی عمل می‌کنه و جلوی هزاران باگ پنهانی رو می‌گیره.

مزایای تست واحد در پروژه‌های سی شارپ

  • کشف سریع باگ‌ها: قبل از اینکه مشکل به محیط production برسه، خودت توی development پیداش می‌کنی.
  • Refactoring بدون ترس: وقتی تست داری، می‌تونی کد رو بهتر کنی بدون اینکه نگران شکستن چیز دیگه‌ای باشی.
  • مستندسازی زنده: تست‌ها خودشون نشون می‌دن که هر متد باید چطور کار کنه.
  • اطمینان از صحت منطق کسب‌وکار: Business Logic پروژه همیشه درست کار می‌کنه.
  • کاهش هزینه نگهداری: رفع باگ در مراحل اولیه بسیار ارزان‌تر از رفع اون در production هست.
  • افزایش اعتماد تیم توسعه: همه اعضای تیم با خیال راحت‌تری کد می‌زنن.

فریمورک‌های محبوب تست در سی شارپ

توی دنیای تست‌نویسی در دات‌نت، چند فریمورک اصلی وجود دارن که هر برنامه‌نویس باید باهاشون آشنا باشه:

۱. MSTest (مایکروسافت)

این فریمورک به صورت پیش‌فرض توی Visual Studio وجود داره و از طرف مایکروسافت پشتیبانی می‌شه. برای پروژه‌های سازمانی بزرگ خیلی مناسبه.

۲. NUnit

یکی از قدیمی‌ترین و محبوب‌ترین فریمورک‌های تست در سی شارپه. جامعه کاربری بزرگی داره و داکیومنتیشن عالی‌ای براش وجود داره.

۳. xUnit

xUnit مدرن‌ترین و محبوب‌ترین فریمورک تست در اکوسیستم دات‌نت جدیده. تیم ASP.NET Core خودشون از xUnit استفاده می‌کنن و این خیلی چیز مهمیه.

شروع عملی: اولین Unit Test با xUnit

بریم سراغ کد! فرض کن یه کلاس ساده Calculator داری که می‌خوای تستش کنی.

مرحله اول: ساخت پروژه تست

توی ترمینال یا Package Manager Console این دستور رو بزن:


dotnet new xunit -n MyProject.Tests

cd MyProject.Tests

dotnet add package xunit

dotnet add package Microsoft.NET.Test.Sdk

مرحله دوم: کلاس اصلی که می‌خوایم تست کنیم


public class Calculator

{

public int Add(int a, int b) => a + b;

public int Subtract(int a, int b) => a - b;

public double Divide(double a, double b)

{

if (b == 0)

throw new DivideByZeroException(“تقسیم بر صفر مجاز نیست!”);

return a / b;

}

}

مرحله سوم: نوشتن تست‌ها با xUnit


using Xunit;

public class CalculatorTests

{

private readonly Calculator _calculator;

public CalculatorTests()

{

_calculator = new Calculator();

}

[Fact]

public void Add_TwoPositiveNumbers_ReturnsCorrectSum()

{

// Arrange

int a = 5, b = 3;

// Act

int result = _calculator.Add(a, b);

// Assert

Assert.Equal(8, result);

}

[Fact]

public void Divide_ByZero_ThrowsException()

{

// Arrange & Act & Assert

Assert.Throws(

() => _calculator.Divide(10, 0)

);

}

[Theory]

[InlineData(10, 2, 5)]

[InlineData(20, 4, 5)]

[InlineData(9, 3, 3)]

public void Divide_ValidInputs_ReturnsCorrectResult(

double a, double b, double expected)

{

double result = _calculator.Divide(a, b);

Assert.Equal(expected, result);

}

}

الگوی AAA: قلب هر Unit Test خوب

توی کد بالا دیدی که از الگوی AAA استفاده کردم. این الگو استانداردترین روش نوشتن تست‌هاست:

  • Arrange (آماده‌سازی): داده‌ها و وابستگی‌های مورد نیاز رو آماده می‌کنی.
  • Act (اجرا): متدی که می‌خوای تست کنی رو صدا می‌زنی.
  • Assert (بررسی): نتیجه رو با مقدار مورد انتظار مقایسه می‌کنی.

Mocking و Dependency Injection در تست‌نویسی

یکی از چالش‌های اصلی در تست‌نویسی واقعی اینه که کلاس‌ها به هم وابسته‌ان. مثلاً یه سرویس به database وصله. توی تست نمی‌خوایم به database واقعی وصل بشیم. اینجاست که Mocking وارد می‌شه.

محبوب‌ترین کتابخونه Mocking در سی شارپ Moq هست. بریم ببینیم چطور کار می‌کنه:


dotnet add package Moq


// Interface که می‌خوایم Mock کنیم

public interface IUserRepository

{

User GetById(int id);

bool Save(User user);

}

// سرویسی که به Repository وابسته‌ست

public class UserService

{

private readonly IUserRepository _repository;

public UserService(IUserRepository repository)

{

_repository = repository;

}

public string GetUserFullName(int userId)

{

var user = _repository.GetById(userId);

if (user == null) return “کاربر یافت نشد”;

return $“{user.FirstName} {user.LastName}”;

}

}

// تست با Moq

public class UserServiceTests

{

[Fact]

public void GetUserFullName_ValidId_ReturnsFullName()

{

// Arrange

var mockRepo = new Mock();

mockRepo.Setup(r => r.GetById(1))

.Returns(new User {

FirstName = “علی”,

LastName = “رضایی”

});

var service = new UserService(mockRepo.Object);

// Act

string result = service.GetUserFullName(1);

// Assert

Assert.Equal(“علی رضایی”, result);

}

[Fact]

public void GetUserFullName_InvalidId_ReturnsNotFoundMessage()

{

// Arrange

var mockRepo = new Mock();

mockRepo.Setup(r => r.GetById(999))

.Returns((User)null);

var service = new UserService(mockRepo.Object);

// Act

string result = service.GetUserFullName(999);

// Assert

Assert.Equal(“کاربر یافت نشد”, result);

}

}

Code Coverage چیست و چقدر باید باشد؟

Code Coverage یا پوشش کد، درصدی از کدته که توسط تست‌ها اجرا می‌شه. مثلاً اگه ۸۰٪ Code Coverage داری، یعنی ۸۰٪ از کدت حداقل یک بار توسط تست‌ها اجرا شده.

برای اجرای تست‌ها و گرفتن گزارش Coverage:


dotnet test --collect:“XPlat Code Coverage”

dotnet tool install -g dotnet-reportgenerator-globaltool

reportgenerator -reports:coverage.xml -targetdir:coverageReport

سوال مهم: باید چقدر Coverage داشته باشیم؟

  • بالای ۸۰٪: ایده‌آل برای اکثر پروژه‌های تجاری
  • ۶۰٪ تا ۸۰٪: قابل قبول برای پروژه‌های در حال توسعه
  • زیر ۶۰٪: نیاز به توجه جدی داره

یه نکته مهم: دنبال ۱۰۰٪ Coverage نباش! بعضی کدها (مثل UI یا کدهای زیرساختی) نیازی به تست واحد ندارن. تمرکزت باید روی Business Logic باشه.

💡 یه سوال از شما داریم!

آیا می‌خواهید سایت شما هم مثل رقبا در صفحه اول گوگل باشد و زنگ‌خورهایتان چند برابر شود؟ سئوی سایت یک سرمایه‌گذاری هوشمندانه است، نه یک هزینه. وقتی مشتریان خودشون شما رو پیدا کنن، دیگه نیازی به هزینه‌های سنگین تبلیغاتی نیست!

سئوی سایت خود را به متخصصان ما بسپارید. همین حالا برای مشاوره رایگان با ما تماس بگیرید:

📞 09190994063  |  📞 09376846692

TDD یا Test Driven Development چیست؟

توسعه آزمون‌محور (TDD) یه رویکرده که توش اول تست می‌نویسی، بعد کد. این رویکرد توی ابتدا عجیب به نظر می‌رسه ولی توی پروژه‌های بزرگ معجزه می‌کنه.

چرخه TDD به این شکله:

  • 🔴 Red: یه تست بنویس که fail بشه (چون کد هنوز نداری)
  • 🟢 Green: حداقل کد لازم رو بنویس که تست pass بشه
  • 🔵 Refactor: کد رو بهتر کن بدون اینکه تست‌ها بشکنن

Integration Test در مقابل Unit Test

خیلی وقت‌ها این دو تا با هم اشتباه گرفته می‌شن. بذار واضح فرقشون رو بگیم:

  • Unit Test: یه واحد کوچک رو تنها و مجزا تست می‌کنه (مثل یه متد یا یه کلاس). سرعت اجرا خیلی بالاست.
  • Integration Test: چند کامپوننت رو با هم تست می‌کنه. مثلاً سرویس + database. کندتره ولی مشکلات یکپارچه‌سازی رو پیدا می‌کنه.
  • End-to-End Test: کل فلوی برنامه از UI تا database رو تست می‌کنه. کندترین نوع تست هست.

بهترین شیوه‌های تست‌نویسی (Best Practices)

  • نام‌گذاری معنادار: اسم تست باید بگه چی تست می‌کنه، با چه ورودی، و چه خروجی انتظار داره. مثال: GetUser_WithValidId_ReturnsUser
  • هر تست فقط یه چیز تست کنه: یه تست نباید چند assertion مختلف داشته باشه که ربطی به هم ندارن.
  • تست‌ها باید مستقل باشن: ترتیب اجرای تست‌ها نباید روی نتیجه تأثیر بذاره.
  • تست‌ها باید سریع باشن: اگه تست کند باشه، کسی اجراش نمی‌کنه.
  • از Magic Number اجتناب کن: بجای عدد مستقیم، از متغیر با نام معنادار استفاده کن.
  • تست Negative Case‌ها رو فراموش نکن: همیشه حالت‌های خطا و استثنا رو هم تست کن.

تست ASP.NET Core Web API

برای تست Controller‌های Web API، می‌تونی از WebApplicationFactory که توی ASP.NET Core وجود داره استفاده کنی:


public class ProductControllerTests : IClassFixture>

{

private readonly HttpClient _client;

public ProductControllerTests(

WebApplicationFactory factory)

{

_client = factory.CreateClient();

}

[Fact]

public async Task GetProducts_ReturnsSuccessStatusCode()

{

// Act

var response = await _client.GetAsync(“/api/products”);

// Assert

response.EnsureSuccessStatusCode();

Assert.Equal(“application/json; charset=utf-8”,

response.Content.Headers.ContentType?.ToString());

}

}

ابزارهای کمکی برای تست‌نویسی در سی شارپ

  • FluentAssertions: نوشتن Assertion‌هایی که خواناتر و طبیعی‌تر به نظر می‌رسن
  • AutoFixture: تولید خودکار داده‌های تست
  • Bogus: تولید داده‌های Fake واقع‌گرایانه
  • Moq: Mock کردن وابستگی‌ها
  • NSubstitute: جایگزین سبک‌تر Moq
  • Coverlet: گزارش Code Coverage

🚀 دیجیتال مارکتینگ هوشمند = رقیبت رو پشت سر بذار!

همون‌طور که یه برنامه‌نویس حرفه‌ای با Unit Test از کدش مراقبت می‌کنه، کسب‌وکار هوشمند هم باید از جایگاه سایتش در گوگل مراقبت کنه. سئوی حرفه‌ای یعنی مشتریانی که دقیقاً دنبال خدمات شما می‌گردن، خودشون شما رو پیدا می‌کنن!

برای مشاوره رایگان سئو همین الان تماس بگیرید: 09190994063 - 09376846692

سوالات متداول (FAQ)

Unit Test و Integration Test چه فرقی دارند؟

Unit Test یک واحد کد (مثل یک متد یا کلاس) رو به صورت کاملاً مجزا و بدون وابستگی خارجی تست می‌کنه. Integration Test چند کامپوننت رو با هم تست می‌کنه و شامل وابستگی‌های خارجی مثل دیتابیس یا API خارجی می‌شه. برای یه پروژه سالم به هر دو نیاز داری.

کدام فریمورک تست برای سی شارپ بهتر است: xUnit یا NUnit؟

هر دو فوق‌العاده‌ان ولی در سال‌های اخیر xUnit به انتخاب اول جامعه دات‌نت تبدیل شده. تیم ASP.NET Core خودشون از xUnit استفاده می‌کنن. اگه پروژه جدید شروع می‌کنی xUnit رو توصیه می‌کنیم. اگه پروژه قدیمی با NUnit داری، نیازی به مهاجرت نیست.

Code Coverage چند درصد باید باشد؟

عدد جادویی وجود نداره! ولی استاندارد صنعت معمولاً ۷۰٪ تا ۸۰٪ رو ایده‌آل می‌دونه. مهم‌تر از درصد، اینه که Business Logic و قسمت‌های حیاتی برنامه حتماً تست داشته باشن. دنبال ۱۰۰٪ Coverage نباش چون وقت و انرژی بیهوده می‌بره.

آیا نوشتن Unit Test وقت زیادی می‌برد؟

بله، در ابتدا کمی وقت بیشتری می‌بره. ولی در بلندمدت وقت خیلی زیادی رو ذخیره می‌کنه. تحقیقات نشون می‌ده که رفع باگ در مرحله تست ۱۰ تا ۱۰۰ برابر ارزون‌تر از رفع اون در production هست. بعد از مدتی تمرین، تست‌نویسی بخش طبیعی کدنویسیت می‌شه.

چطور کلاس‌هایی که به دیتابیس وصلن رو تست کنیم؟

دو روش اصلی وجود داره: اول استفاده از Mock (مثل Moq) که وابستگی دیتابیس رو جایگزین می‌کنه و تست رو خیلی سریع نگه می‌داره. دوم استفاده از In-Memory Database که EF Core پشتیبانی می‌کنه. برای Unit Test از Moq و برای Integration Test از In-Memory Database استفاده کن.

آیا Static Method‌ها رو می‌توان Unit Test کرد؟

تست کردن Static Method‌ها ممکنه ولی Mock کردنشون سخته. توصیه می‌شه از Static Method‌ها برای Business Logic پیچیده اجتناب کنی و از Dependency Injection استفاده کنی. ابزارهایی مثل Microsoft Fakes یا Pose می‌تونن Static Method‌ها رو هم Mock کنن ولی اضافه‌کاری غیرضروری ایجاد می‌کنن.

جمع‌بندی

تست‌نویسی یه مهارت حرفه‌ایه که هر برنامه‌نویس سی شارپ باید یاد بگیره. با شروع از Unit Test‌های ساده و تمرین مداوم، به زودی می‌تونی با اطمینان بیشتری کد بزنی و محصول بهتری تحویل بدی. همیشه یادت باشه: کد بدون تست، کد نصفه‌ست!

نمایش کد

نظرات کاربران