استفاده از Unit Testing بر اساس TDD مخفف Test Driven Development

یکشنبه 18 بهمن 1394

در این مقاله قصد داریم راجع به TDD صحبت کنیم .برای درک بهتر در یک مثال ساده این طراحی را پیاده سازی خواهیم کرد .TDD یک روشی است که در آن قبل از اینکه به صورت معمول شروع به نوشتن نرم افزار با کلاس ها و توابع مختلف بنویسیم ، ابتدا یک تست برای نیازهای خاص خود می نویسیم

استفاده از Unit Testing بر اساس TDD مخفف Test Driven Development

قبل از اینکه راجع به موضوع اصلی مقاله یعنی TDD یا (Test-Driven Development)  صحبت کنیم کمی راجع به Unit Test صحبت خواهیم کرد. Unit Test یعنی تست یک بخش خاص از نرم افزار که یک کار خاص را برای ما انجام می دهد .یعنی به وسیله کدهایی که شما به عنوان برنامه نویس می نویسید ، عملکرد قطعات دیگری از کد سنجیده خواهند شد .قصد داریم که مثلا یک متد یا تکه کدی که جدیدا به برنامه اضافه شده است را تست کنیم که آیا درست کار می کند یا خیر.

کدهایی که به منظور تست نوشته می شوند داخل یک کلاس هستند .این کلاس قوانین خاصی دارد و از جمله اینکه باید توسط صفت های خاصی Annotation و یا حاشیه نویسی شود .خود کلاس باید با صفت [TestFixture] حاشیه نویسی شود .برای نوشتن کارهای setup کلاس تست باید یک متد با حاشیه [SetUp] بنویسیم .متدی که صفت  [TearDown]را دارد بعد از اجرای هر تست اجرا می شود .متدهایی هم که برای تست نوشته شده اند دارای صفت [Test] هستند.

TDD یک روشی است که در آن قبل از اینکه به صورت معمول شروع به نوشتن نرم افزار با کلاس ها و توابع مختلف بنویسیم ، ابتدا یک تست برای نیازهای خاص خود می نویسیم .در این تست با کمترین کد و با ورودی های مناسب خروجی ایی را که مدنظرمان است از کد می گیریم .TDD یک روش بالا به پایین است .همان کدهای تستی که به شما گفتیم (با ورودی های مشخص ، خروجی مد نظر ما را ارائه می دهند ) در واقع Mock هایی هستند که در نهایت با کدهای اصلی برنامه جایگزین می شوند .بعد از نوشتن Mock ها Refactoring صورت می گیرد.تفاوت TDD با UnitTest این است که TDD یک روش برای طراحی نرم افزار است تا تست آن .برای اجرای TDD نیاز به Automated Test Unit داریم .در واقع تست ها قبل از کد پیاده سازی می شوند و تنها true یا false برمی گردانند .ابزارهای مختلفی برای unit Test وجود دارد که در دات نت این ابزار NUnit نام دارد . چرخه حیات یک روش TDD به این صورت است که ابتدا تست ها را می نویسیم ، بار اول که اجرا کنیم همه تست ها fail خواهد شد .بعد از این کار کدهای مربوط Pass شدن تست ها را می نویسیم .بعد از این کار دوباره تست ها را اجرا می کنیم .در این حالت تست های تماما pass خواهند شد .در نهایت عمل Refactoring را انجام می دهیم .

برای تست روش TDD به صورت عملی مراحل زیر را انجام می دهیم .یک پروژه از نوع MVC و با نوع Empty ایجاد می کنیم.در داخل پوشه مدل (دقت کنید که هیچ منطق و کدی برای برنامه ننوشته ایم و شروع کرده ایم به نوشتن TDD) ، یک کلاس Idea ایجاد می کنیم .این کلاس به صورت زیر است .

  public class Post
    {


        public static List<Post> Posts = new List<Post>
        {
            new Post {Content = "پست های مربوط به برنامه نویسی", Title = "سایت برنامه نویسان"},
            new Post {Content = "چهارچوب دات نت و برنامه نویسی با محصولات دات نت", Title = "دات نت"},
        };

        public string Content { get; set; }
        public string Title { get; set; }
    }

این کلاس علاوه بر پراپرتی های خود دارای یک پراپرتی static از نوع لیستی از خودش هم هست .

حال کلاس تست را می نویسیم .نام این کلاس IdeaTest است .این کلاس دارای صفت  [TestFixture] است .سه تابع تست در داخل این کلاس نوشته ایم .

کد تست اول که یک تابع است در زیر آورده شده است .

 [Test]
        public void ShouldDisplayListOfIdea()
        {
            var viewResult = new PostController().Index() as ViewResult;
            Assert.AreEqual(Post.Posts, viewResult.Model);
            Assert.IsNotNull(viewResult.Model);
        }

در این تابع ابتدا یک کنترلر از نوع کنترلر Postکه هنوز ایجاد نکرده ایم ساخته ایم .و سپس ازاین کنترلر و اکشن Index درون آن که  از نوع actionResult است  یک متغیر به نام viewResult تعریف کرده ایم .بعد از توابعی که در داخل کتابخانه assert وجود دارد استفاده کرده ایم و چک کرده ایم مدلی که به داخل viewResult پاس داده می شود از نوع Post باشد و همچنین چک کرده ایم که خالی نباشد . اگر تست را اجرا کنیم ، خطا خواهیم گرفت ؟ خیلی ساده است به خاطر اینکه اصلا کنترلر idea در برنامه وجود ندارد .حال این کنترلر و اکشن Index ان را با مدلی از جنس Post ایجاد می کنیم .کد کنترلر به صورت زیر است

   public class PostController : Controller
    {
        // GET: post
        public ActionResult Index()
        {
            return View(Post.Posts);
        }

حال در داخل کلاس تست خود یک تست دیگر می نویسیم .این تست را برای چک کردن اینکه یک Action و view مربوط هم نام با آن وجود دارد می سازیم.کد این تست به صورت زیر است .

  [Test]
        public void ShouldLoadCreateIdeaView()
        {
            var viewResult = new PostController().Create() as ViewResult;
            Assert.AreEqual(string.Empty, viewResult.ViewName);
        }

در این تست میخواهیم  از وجود داشتن یک Action و نام view بازگشتی اطمینان حاصل کنیم.یک نمونه از کنترلر ایجاد کرده و سپس نام view ایی که بازگشت داده می شود را با string.Empty مقایسه می کنیم .این کار باعث می شود view ما نام نداشته باشد و با نام اکشن خود یکی باشد .حال باید در داخل برنامه تست خود را پیاده سازی کنیم .

    public ActionResult Create()
        {
            return View();
        }

حال تست سوم را می نویسیم.در این تست یک post ایجاد کرده ایم این شی قرار است به داخل لیست posts اضافه شود .

  [Test]
        public void ShouldAddIdeaItem()
        {
            var post = new Post { Title = "فروم برنامه نویسان ", Content = " سوالات برنامه نویسی را بپرسید" };
            var redirectToRouteResult = new PostController().Create(post) as RedirectToRouteResult;
            Assert.Contains(post, Post.Posts);
            Assert.AreEqual("Index", redirectToRouteResult.RouteValues["action"]);
        }

 

در این تست از کنترلر Post و از اکشن ()Create که دارای یک پارامتر است یک نمونه ایجاد کرده ایم .اما نوع این نمونه را RedirectToRouteResult در نظر گرفته ایم .بعد از این چک می کنیم که این شی در داخل لیست Posts وجود دارد یا خیر. نهایتا هم این اکشن را به اکشن Index هدایت کرده ایم .

تست بالا نیز مانند دو تست قبل است با این تفاوت که میخواهیم Redirect شدن به یک Action  خاص را نیز تست کنیم.برای همین مقدار خروجی را به RedirectToRouteResult تبدیل می‌کنیم.در ادامه یک Idea جدید ساخته و به لیست اضافه میکنیم سپس از وجود داشتن آن در لیست Ideas اطمینان حاصل می‌کنیم.در خط آخر نیز نام Action که انتظار داریم بعد از اضافه شدن یک Idea ,کاربر به آن هدایت شود را ست می‌کنیم.

تا به اینجا با مفهوم TDD و نحوه نوشتن آن اشنا شدید .شاید حس کنید که دوبار دارید کد نویسی می کنید(ابتدا تست را نوشتید و بعد خود کد را پیاده سازی کردید) و این خوب نیست .ولی این طور نیست مدل طراحی TDD مزایای بسیاری دارد که به ذکر چند مورد می پردازیم .

1-حجم نهایی کدها کمتر است

چون کدی خواهید نوشت که از صحت عملکرد آن مطمئن هستید حجم کدهای نهایی پایین خواهد بود .

2- طراحی بهتر

با کمک این سبک طراحی قواعد SOLID خود به خود رعایت می شوند.

3- ارتباط بین برنامه نویس و کاربر نهایی سیستم بهتر خواهد بود .زیرا کاربر و یا کارفرما می تواند در فرآیند توسعه نرم افزار شرکت داشته باشد .

4- با این روش کدهایی بی استفاده نخواهیم داشت .

5- با نوشتن یک تست و پاس شدن آن می توانید کل تست ها را اجرا کنید و به این ترتیب مطمئن خواهید شد که کد جدید اثر جانبی بر سایر بخش های برنامه نداشته باشد .

فایل های ضمیمه

برنامه نویسان

نویسنده 3355 مقاله در برنامه نویسان

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید