اگر یه برنامهنویس سی شارپ هستی و هنوز تستنویسی رو جدی نگرفتی، باید صادقانه بگم که داری یکی از مهمترین مهارتهای دنیای امروز توسعه نرمافزار رو نادیده میگیری. Unit Test یا تست واحد یعنی نوشتن کدی که کد دیگهات رو تست میکنه. ساده به نظر میرسه، ولی تأثیرش روی کیفیت، نگهداری و اطمینان از کد شما فوقالعادهست.
تصور کن یه پروژه بزرگ داری و یه تغییر کوچیک توی یه کلاس میدی. چطور مطمئن میشی که بقیه قسمتهای برنامه خراب نشدن؟ اینجاست که Unit Test مثل یه شبکه ایمنی عمل میکنه و جلوی هزاران باگ پنهانی رو میگیره.
توی دنیای تستنویسی در داتنت، چند فریمورک اصلی وجود دارن که هر برنامهنویس باید باهاشون آشنا باشه:
این فریمورک به صورت پیشفرض توی Visual Studio وجود داره و از طرف مایکروسافت پشتیبانی میشه. برای پروژههای سازمانی بزرگ خیلی مناسبه.
یکی از قدیمیترین و محبوبترین فریمورکهای تست در سی شارپه. جامعه کاربری بزرگی داره و داکیومنتیشن عالیای براش وجود داره.
xUnit مدرنترین و محبوبترین فریمورک تست در اکوسیستم داتنت جدیده. تیم ASP.NET Core خودشون از 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;
}
}
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 استفاده کردم. این الگو استانداردترین روش نوشتن تستهاست:
یکی از چالشهای اصلی در تستنویسی واقعی اینه که کلاسها به هم وابستهان. مثلاً یه سرویس به 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 داری، یعنی ۸۰٪ از کدت حداقل یک بار توسط تستها اجرا شده.
برای اجرای تستها و گرفتن گزارش 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) یه رویکرده که توش اول تست مینویسی، بعد کد. این رویکرد توی ابتدا عجیب به نظر میرسه ولی توی پروژههای بزرگ معجزه میکنه.
چرخه TDD به این شکله:
خیلی وقتها این دو تا با هم اشتباه گرفته میشن. بذار واضح فرقشون رو بگیم:
GetUser_WithValidId_ReturnsUserبرای تست 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()); } }
🚀 دیجیتال مارکتینگ هوشمند = رقیبت رو پشت سر بذار!
همونطور که یه برنامهنویس حرفهای با Unit Test از کدش مراقبت میکنه، کسبوکار هوشمند هم باید از جایگاه سایتش در گوگل مراقبت کنه. سئوی حرفهای یعنی مشتریانی که دقیقاً دنبال خدمات شما میگردن، خودشون شما رو پیدا میکنن!
برای مشاوره رایگان سئو همین الان تماس بگیرید: 09190994063 - 09376846692
Unit Test یک واحد کد (مثل یک متد یا کلاس) رو به صورت کاملاً مجزا و بدون وابستگی خارجی تست میکنه. Integration Test چند کامپوننت رو با هم تست میکنه و شامل وابستگیهای خارجی مثل دیتابیس یا API خارجی میشه. برای یه پروژه سالم به هر دو نیاز داری.
هر دو فوقالعادهان ولی در سالهای اخیر xUnit به انتخاب اول جامعه داتنت تبدیل شده. تیم ASP.NET Core خودشون از xUnit استفاده میکنن. اگه پروژه جدید شروع میکنی xUnit رو توصیه میکنیم. اگه پروژه قدیمی با NUnit داری، نیازی به مهاجرت نیست.
عدد جادویی وجود نداره! ولی استاندارد صنعت معمولاً ۷۰٪ تا ۸۰٪ رو ایدهآل میدونه. مهمتر از درصد، اینه که Business Logic و قسمتهای حیاتی برنامه حتماً تست داشته باشن. دنبال ۱۰۰٪ Coverage نباش چون وقت و انرژی بیهوده میبره.
بله، در ابتدا کمی وقت بیشتری میبره. ولی در بلندمدت وقت خیلی زیادی رو ذخیره میکنه. تحقیقات نشون میده که رفع باگ در مرحله تست ۱۰ تا ۱۰۰ برابر ارزونتر از رفع اون در production هست. بعد از مدتی تمرین، تستنویسی بخش طبیعی کدنویسیت میشه.
دو روش اصلی وجود داره: اول استفاده از Mock (مثل Moq) که وابستگی دیتابیس رو جایگزین میکنه و تست رو خیلی سریع نگه میداره. دوم استفاده از In-Memory Database که EF Core پشتیبانی میکنه. برای Unit Test از Moq و برای Integration Test از In-Memory Database استفاده کن.
تست کردن Static Methodها ممکنه ولی Mock کردنشون سخته. توصیه میشه از Static Methodها برای Business Logic پیچیده اجتناب کنی و از Dependency Injection استفاده کنی. ابزارهایی مثل Microsoft Fakes یا Pose میتونن Static Methodها رو هم Mock کنن ولی اضافهکاری غیرضروری ایجاد میکنن.
جمعبندی
تستنویسی یه مهارت حرفهایه که هر برنامهنویس سی شارپ باید یاد بگیره. با شروع از Unit Testهای ساده و تمرین مداوم، به زودی میتونی با اطمینان بیشتری کد بزنی و محصول بهتری تحویل بدی. همیشه یادت باشه: کد بدون تست، کد نصفهست!