صفحه شخصی سید علا سبزپوش

برنامه نویس دات نت و sql_server --ریاضیات

صفحه شخصی سید علا سبزپوش

برنامه نویس دات نت و sql_server --ریاضیات

nunit Test

کار با unit test

در بخشهای قبلی در مورد دلایل تست صحبت کردم و گفتم که ما برای کار نیاز به ابزار تست داریم . یکی از این ابزارهای unit test  است که شما می توانید از آدرس زیر آن را دانلود و نصب کنید . http://www.nunit.org/

پس از دانلود و نصب نرم افزار ، اکنون وقت آن است که با یک پروژه عملی نحوه کار را آموزش دهیم ، برای اینکار یک کلاس می خواهیم بسازیم که این کلاس دارای یک متد است که به دنبال یک فایل با پسوند slf  می گردد . در واقع نام این فایل و پسوند به این متد ارسال می شود و در صورتی که چنین فایلی با این پسوند موجود نباشد پیغام خطا صادر می شود و در غیر اینصورت اگر پسوندی غیر از Slf  باشد پیغام نادرست بودن می دهد . سورس کلاس برنامه ما بصورت زیر است . شما ابتدا یک پروژه از نوع کلاس ایجاد کنید و سپس کدهای زیر را برای تولید کلاس بنویسید :

using System;

using System.IO;

namespace LogAn

{

    public class LogAnalyzer

    {

        public bool IsValidLogFileName(string fileName)

        {

            if (!File.Exists(fileName))

            {

                throw new Exception("No log file with that name exists");

            }

            if(!fileName.ToLower().EndsWith(".slf"))

            {

                return false;

            }

          

            return true;

        }

    }

}

کد بالا در واقع کد کلاس ما هستند اکنون ما می خواهیم برای کلاس بالا یک unit test  بنویسیم می خواهیم عملکرد کد بالا را تست کنیم .

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

نام پروژه : در پروژه بالا نام پروژه کلاس ما LogAn  بود . حال برای پروژه تست چه نامی انتخاب کنیم . فرمول آن بصورت زیر است .                       Tests. نام پروژه این روش نام گذاری بهتر است  مثلا برای پروژه کلاس بالا ، پروژه تست با نام  تحت عنوان    LogAn.Tests  خواهد بود .

نام کلاس : در پروژه بالا نام کلاس ما LogAnalyzer  است .اکنون که می خواهیم برای آن کلاس تست بنویسیم بهتر است که کلاس تست را بر اساس فرمول   s Testنام کلاس  بنویسیم مانند : LogAnalyzerTests

نام متد : ما یکسری متدها برای تست داریم اینجا باید مشخص و خوانا باشد که این متد قرار است کدام متد کلاس اصلی را تست کند برای اینکار از فرمول        حالت رفتاری_نوع حالت تحت تست_نام متد  استفاده شود البته این عبارت حاصل ترجمه عبارت انگلیسی زیر است . [MethodName]_[StateUnderTest]_[ExpectedBehavior]

حالا با توجه به توضیح قوانین بالا یک پروژه جدید با نام LogAnTests  ایجاد می کنیم برای تست پروژه کلاس بالا ابتدا باید دو فایل مرجع یا refrence  را به پروژه اضافه کنیم قسمت Add Refrence  پروژه را انتخاب کنید و فایل dll  پروژه بالا را اضافه کنید همچنین از محل نصب نرم افزار unit test  باید nunit.framework  را به پروژه خود اضافه کنید . اکنون بر اساس قوانین ذکر شده در بالا کلاس تست را به صورت زیر می نویسیم .

using System;

using NUnit.Framework;

namespace LogAn.Tests

{

    [TestFixture]

    public class LogAnalyzerTests

    {

        private LogAnalyzer m_analyzer=null;

       

        [SetUp]

        public void Setup()

        {

           

            m_analyzer = new LogAnalyzer();   

        }

       

        [Test]

        [Ignore("This test is broken")]

        public void IsValidFileName_validFileLowerCased_ReturnsTrue()

        {

            bool result = m_analyzer.IsValidLogFileName("whatever.slf");

           

            Assert.IsTrue(result, "filename should be valid!");

        }

       

        [Test]

        public void IsValidFileName_validFileUpperCased_ReturnsTrue()

        {

            bool result = m_analyzer.IsValidLogFileName("WHATEVER.SLF");

           

            Assert.IsTrue(result, "filename should be valid!");

        }

       

        [Test]

        [ExpectedException(typeof(Exception),"No log file with that name exists")]

        public void IsValidFileName_nunintvalidFileUpperCased_ReturnsTrue()

        {

            bool result = m_analyzer.IsValidLogFileName("whatever.SLF");

           

            Assert.IsTrue(result, "filename should be valid!");

        }

        [TearDown]

        public void TearDown()

        {

            m_analyzer = null;

        }

    }

}

فراموش نکنید که سطح دسترسی کلاس ما باید عمومی  public  باشد تا در حین آنالیز قابل دسترسی باشد .اکنون باید ویژگیهایی که به کلاس بالا اضافه کنیم این ویژگیها حکم تفسیر برای تست دارند که حتما باید در تست نوشته شوند .

اگر به ابتدای تست دقت کنید اول از همه ویژگی  TestFixture  را می بینید این ویژگی به نرم افزار nunit  اعلام می کند که این کلاس تحت عمل تست است .

SetUp   : ممکن است ما بخواهیم تستی را برای چند مرتبه تکرار کنیم . ما در هر بار اجرای تست باید ابتدا نمونه ای از کلاس را ایجاد کنیم و پس از اتمام تست آن نمونه از بین برود یا پاک شود . همچنین برای ایجاد یک نمونه خالی و جدید از کلاس تحت تست ما از این قسمت استفاده می کنیم . که در هر بار اجرای تست یک نمونه جدید از کلاس می سازد .تا با نمونه های قبلی تداخل ایجاد نکند .

TearDown : در واقع مکمل و پایان دهنده setup   است چرا که پس از پایان تست آن نمونه از کلاس که تحت تست است باسد از پاک شود و از بین برود که دراین قسمت ما بصورت واضح می توانیم نحوه از بین بردن نمونه کلاس را اعلام کنیم.

 درواقع یک تست از setup  آغاز می شود و پس از اجرای فرآیندهای مختلف و متدهای مختلف با TearDown  پایان می یابد مانند شکل زیر :

 

Test  : در واقع بدنه متدهای تست را نشان می دهد .

Ignore : در برخی مواقع تست ما با شکست مواجه می شود ما باید حالتی برای عدم توقف و شکست داشته باشیم که این حالت بهترین حالت است .

اکنون پروژه خود را کامپایل کنید تا فایل dll آن ایجاد شود . خوب حالا برنامه nunit  را اجرا کنید و از منوی File آن یک پروژه جدید را آغاز نموده و آنرا ذخیره کنید.سپس دوباره از همان منو و از قسمت open project  فایل dll  پروژه را باز کنید . فایلهای پروژه باز می شوند دکمه اجرای تست را بزنید تا تست شما اجرا شود .اگر سبز رنگ بود یعنی تست با موفقیت انجام شد اما جاهایی که قرمز رنگ است یعنی تست شما دارای اشکال است که باید برای آن حالت تغییری در کد ایجاد کنید

مقوله nunit بسیار مفصل است لذا تا همینجا اکتفا می کنم اما توجه شما را به این نکته جلب می کنم که برادر گرامی وحید نصیری در وبلاگ خود وطالب مفصلی را در این زمینه منتشر کرده اند که می توانید از لینک زیر مطالعه کنید .

چرا از ابزار تست استفاده می کنیم ؟

بخش ۳ 


Frameworks for Unit testing


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

 

بدون ابزار تست چه محدودیتهایی خواهیم داشت

 

1-تستهای ما فاقد ساختار منسجم است . یعنی در واقع ما برای اجرای تست قانونی نداریم و برای هر قطعه کد به دلخواه تستی خواهیم نوشت و این باعث پیچیدگی تست می شود .

 

2-تست ما تکرار پذیر نیست . از مهمترین نکات تست قابلیت تکرار است . به طوری که همزمان با توسعه نرم افزار تستها باید تکرار شوند .

 

3-شما نمی توانید برای تمام کد هایتان تست بنویسید . در واقع مجتمع سازی تستها ، بدون استفاده از ابزار های تست کاری سخت و غیر ممکن است .

 

با استفاده از ابزار تست چه مشکلاتی حل می شود .

 

1-تستها قانونمند می شود و به آسانی نوشته می شوند .چرا که این ابزارها دارای مجموعه ای از کتابخانه های آماده برای تسهیل عمل تست هستند.

 

2-اجرای یکباره و چند باره تست آسان می شود . در واقع این ابزارها به کمک امکاناتی که دارند تکرار پذیری تست را آسان می کند و شما می توانید پیشرفت تست و یا حالتهای تست را ارزیابی کنید

 

3-مشاهده نتایج حاصل از تست . شما می توانید با کمک ین ابزارها بدانید که چه تعداد تست در حال اجرا است یا اجرا شده است .کدام تست با مشکل مواجه شده و دلیل شکست تست چه بوده و.....

 

از چه ابزاری استفاده کنیم .

ابزارهای تست فراوان است اما من می خواهم بر روی ابزار xUnit  تمرکز کنم و سعی می کنم به معرفی این ابزار بپردازم . این ابزار به آنها xUnit Frameworks  گفته می شود .که حرف اول x   نشان دهنده زبان مورد پشتیبانی است مثلا برای زبان جاوا jUnit   و برای دات نت NUnit  و ..

 

شما می توانید این ابزار را از سایت http://www.nunit.org/  دریافت کنید .


زمان نوشتن تست

بخش ۲

در بخش قبل گفتم که برای نرم افزار ما باید تست نوشت و خصوصیات لازم را ذکر کردم . اما سوال این است که چه زمانی باید تست را نوشت . در دید سنتی و شاید قدیم گفته تصور می شد که تست را باید بعد از نوشتن کدها نوشت . اما به مرور زمان معایب آن آشکار شد . از مهمترین معایب آن شاید بی حوصلگی و عدم تمایل برای تست است و از همه مهمتر مستند نشدن صحیح فرآیند کد نویسی است .

برای حل این مشکل مفهوم Test Driven development  مطرح شد که که مخفف آن همان TDD  است .

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

اکنون برای فهم بهتر به دوشکل زیر نگاه کنید در تصویر اول توسعه و تست بر اساس کد نویسی اول و در آخر تست انجام می شود



اما در شکل 2 بر اساس TDD  است . ابتدا تست را می نویسیم .همانطور که در شکل پایین می بینید یک حلقه مارپیچی جالبی می بینید که ابتدا تستها نوشته می شوند ترتیب اعمال ما بصورت زیر است

1-نوشتن تست  2-نوستن کدها ۳-refactor 

4-نوشتن تست بعدی



حال با توجه به شکل بالا مختصری توضیح می دهم .

1-ما برای نوشتن تست ابتدایی در واقع تستی را می نویسیم برای حالتی  که کد ما دچار خطا شود مثلا اگر تقسیم دو عدد باشد ما در تست عدد صفر را به مخرج می فرستیم تا نتیجه خطا را مشاهده کنیم در واقع ما در تست درست بودن را تست نمی کنیم به تعبیری دیگر ما  با داده ها قابل قبول تست نمی کنیم بلکه تست ما بر اساس داده ها غیر قابل قبول است تا برای آنها شرایط قابل کنترل فراهم کنیم .

 

2-کدهای خود را بر اساس تستها به گونه ای می نویسیم که بتوانند تستها را به درستی پاس کنند .

 

3-refactor  یعد از اینکه شما تست را پاس کردید ، شما به تست بعدی منتقل می شوید .یا شاید برای خوانایی و بهتر شدن کد عمل refactor  را برروی کدهای خود اعمال کنید .

 

نکته : refactor  یعنی تغییر دادن قطعه ای از کد برای خوانایی بهتر ، بدون آنکه عملکرد آن قطعه کد دچار تغییر شود .

اما برای فهم جالبتر موضوع لینک زیر را قرار دادم که دوستان می توانند برای فهم بهتر آن را مطالعه کنند .


آیا TDD در عمل امکان پذیر می باشد؟