انجام Unit Testing در سی شارپ و .Net Core با xUnit

پرووید

دسته های مقالات

در این آموزش از وبسایت پرووید قصد داریم به صورت قدم به قدم شما را در رابطه با ساخت یک پروژه و انجام Unit Testing در .Net Core و آشنایی با مفاهیم آن همراهی کنیم. دقت کنید که توصیه می ‌کنیم قبل از استفاده از این مقاله حتماً از بسته ی ویدئویی آموزش Unit Testing وبسایت پرووید استفاده کنید. ضمنا میتوانید با استفاده از این لینک به کدهای مربوط به این آموزش نیز دسترسی پیدا کنید.

ساخت پروژه

در این آموزش از وبسایت پرووید ما کار را با استفاده از dot net CLI انجام می‌دهیم. آموزش های دیگری از وبسایت پرووید از قبل منتشر شده‌اند که در رابطه با کار کردن و ساخت پروژه ها و فایلهای solution با استفاده از CLI که مخفف Command Line Interface می‌ باشد منتشر شده اند. خب CLI را باز کنید و یک فولدر با نام unit-testing-using-dotnet-test ایجاد کنید.

این فولدر حاوی solution مورد نظر خواهد بود. در درون این فولدر دستور dotnet new classlib را وارد کنید تا یک solution جدید ایجاد شود. با استفاده از این دستور و ساختن یک solution میتوانید هم پروژه class library و هم پروژه unit test را مدیریت کنید. در درون فولدری که برای solution در نظر گرفته اید یک فولدر با نام PrimeService ایجاد کنید. تا به اینجا ساختار فولدرهای برنامه شبیه زیر می باشند.

solution-structure

فولدر PrimeService را به عنوان current directory در نظر گرفته و دستور dotnet new classlib را اجرا کنید. این موضوع باعث ساخته شدن یک class library جدید می شود. فایل Class1.cs را به PrimeService.cs تغییر نام دهید. اگر می خواهید با استفاده از اصول TDD یا همان Test Driven Development کار کنید اول باید تستی را برای کلاس PrimeService بنویسید که fail شود. در ادامه کد مربوط به PrimeService.cs را مشاهده می کنید.

 
using System;

namespace Prime.Services
{
    public class PrimeService
    {
        public bool IsPrime(int candidate)
        {
            throw new NotImplementedException("Please create a test first");
        }
    }
}

در ادامه پروژه class library را به solution خود اضافه کنید. این موضوع در کد زیر نشان داده شده است:

 
dotnet sln add .PrimeServicePrimeService.csproj

ساختن پروژه unit test

در ادامه یک فولدر با نام PrimeService.Tests ایجاد کرده تا ساختار پروژه ها و فولدرهای برنامه شبیه زیر شود.

solution-structure

فولدر PrimeService.Tests را به عنوان current directory تنظیم کنید و با استفاده از دستور dotnet new xunit یک پروژه جدید ایجاد کنید.

این دستور باعث می شود که یک پروژه برا انجام unit testing با استفاده از xUnit ایجاد شود. علاوه بر این پیکربندی های مربوط به test runner در درون فایل PrimeServiceTests.csproj شبیه کد زیر انجام می شود.

 

  
  
  

برای اینکه پروژه ی unit test بتواند تست ها را ایجاد کند و آنها را Run کند نیاز به dependency های دیگری دارد. دستور dotnet new در قسمت قبلی xUnit و xUnit Runner را به عنوان dependency به پروژه اضافه کرد. هم اکنون ما نیاز به یک رفرنس به پروژه ی PrimeService به عنوان یک Dependency دیگر برای این پروژه داریم که با استفاده از دستور dotnet add reference شبیه به کد زیر این موضوع انجام می شود:

 
dotnet add reference ../PrimeService/PrimeService.csproj

در حال حاضر ساختار نهایی solution های برنامه شبیه به زیر می باشد.

solution-structure

برای اضافه کردن پروژه ی unit test خود به solution با استفاده از دستور dotnet sln این کار را انجام می‌ دهیم. کد مربوط به این قضیه نیز در قسمت پایین مشخص شده است.

 
dotnet sln add .PrimeService.TestsPrimeService.Tests.csproj

ساخت اولین unit test

اگر با روش test-driven development آشنا هستید که آموزش‌های کاملی از آن نیز بر روی وبسایت پرووید قرار گرفته است می‌دانید که اولین قدم در test-driven development نوشتن یک test ی است که با fail می شود. و سپس پیاده‌ سازی کدی که باعث pass شدن آن test می ‌شود و پس از آن انجام ریفکتورینگ. در این آموزش ما فایل UnitTest1.cs را حذف کرده و یک فایل با نام PrimeService_IsPrimeShould.cs. اضافه می‌کنیم. کد زیر محتویات این فایل را نشان می‌دهد.

 
using Xunit;
using Prime.Services;

namespace Prime.UnitTests.Services
{
    public class PrimeService_IsPrimeShould
    {
        private readonly PrimeService _primeService;

        public PrimeService_IsPrimeShould()
        {
            _primeService = new PrimeService();
        }

        [Fact]
        public void ReturnFalseGivenValueOf1()
        {
            var result = _primeService.IsPrime(1);

            Assert.False(result, "1 should not be prime");
        }
    }
}

همانطور که در کد بالا مشاهده می کنید یک attribute با نام [Fact] بر روی test method قرار گرفته که به test runner می گوید که این متد یک test method می ‌باشد. از طریق فولدر PrimeService.Tests دستور dotnet test را اجرا کرده تا test ها و class library ساخته شده build و سپس run شوند.

در واقع test runner مربوط به xUnit حاوی entry point یا نقطه شروع مربوط به برنامه به منظور run کردن test ها می باشد و دستور dotnet test باعث می شود که test runner شروع شود و پروژه unit test ای که ایجاد کرده اید اجرا شود. بدون شک تست شما در این مرحله fail خواهد شد چرا که هیچ پیاده سازی برای متد Is Prime در کلاس PrimeService انجام نداده اید. لطفاً کدی که در قسمت زیر می‌بینید را به عنوان پیاده سازی این متد لحاظ کنید و سپس دستور dotnet test را از فولدر PrimeService.Tests اجرا کنید.

 
public bool IsPrime(int candidate)
{
    if (candidate == 1)
    {
        return false;
    }
    throw new NotImplementedException("Please create a test first");
}

دستور dotnet test باعث build شدن و run شدن پروژه PrimeService و سپس PrimeService.Tests می شود. خوشبختانه در این مرحله این تست pass خواهد شد.

افزودن قابلیت های بیشتر

حال که توانسته اید test اول را pass کنید زمان نوشتن test های بیشتر است. دقت کنید که برای اعداد اول یا همان prime number ها که برنامه به منظور در نظر گرفتن و ساختن آنها انجام شده است موارد دیگری نیز از قبیل صفر و منفی یک وجود دارند. می شود این موارد را هم نیز در قالب test method هایی که با عطر attribute ای با نام [Fact] مشخص می‌ شوند ایجاد کرد. اما این روش روش مناسبی نیست.

در xUnit ما می توانیم با استفاده از attribute های دیگری test های مشابه ایجاد کنیم. یکی از این attribute ها [Theory] و دیگری این [InlineData] می باشد.

در این آموزش ها در رابطه با xUnit و ویژگی های مختلفی که ارائه می ‌کند صحبت کرده ایم. خب [Theory] به شما کمک می کند که مجموعه ای از test های مشابه که یک کد مشترک و یکسان را تست می‌کند اما پارامترهای ورودی مختلفی را دارند ایجاد کنید و [InlineData] برای مشخص کردن مقادیر این پارامترهای ورودی می باشد.

بنابراین به منظور بررسی کردن موارد دیگر از اعداد اول از قبیل صفر و منفی یک به جای اینکه تست های جدید بنویسیم attribute های [Theory] و [InlineData] را استفاده می کنیم تا بتوانیم یک تست یکسان در فایل PrimeService_IsPrimeShould.cs. ایجاد کنیم.

 
[Theory]
[InlineData(-1)]
[InlineData(0)]
[InlineData(1)]
public void ReturnFalseGivenValuesLessThan2(int value)
{
    var result = _primeService.IsPrime(value);
    
    Assert.False(result, $"{value} should not be prime");
}

این theory یک متد است که مقادیر مختلفی را که کوچکتر از دو هستند را تست می‌کند. این موضوع در کد زیر نشان داده شده است.

با اجرا کردن این تستها که در واقع سه تست مختلف میباشند دو تا از آنها fail خواهند شد. به منظور pass شدن همه آنها دستور if ی که در قسمت ابتدایی متد IsPrime قرار گرفته است را به شکل (candidate < 2) تغییر دهید.

خب امیدواریم که این آموزش از وبسایت پرووید نیز مورد توجه شما قرار گرفته باشد. در این آموزش به صورت ابتدایی در رابطه با unit testing در .NET Core و سی شارپ صحبت کردیم.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *