Unit Testing چیست؟

در این پست می خواهم درباره Unit Testing یا تست واحد صبحت کنم و اینکه چطور با استفاده از Unit Testing می توانیم محصول با کیفیت تر و توسعه راحت تری داشته باشیم.

Unit Testing چیست؟

Unit Testing یا تست واحد روشی هستش که با استفاده از اون درست کار کردن یک قطعه کد (کوچک ترین واحد قابل تست از برنامه) را بررسی می کنیم. همچنین بررسی کنیم که قطعه کد مورد نظر طبق انتظار اجرا و خروجی می دهد یا خیر. برای این بررسی ها به سراغ طراحی Test Case ها می رویم که با اجرای اون ها قطعه کد مورد نظر با ورودی های مختلف و یا شرایط مختلف اجرا و رفتار قطعه کد را ارزیابی می کند.

اجرای موفق تست های تعریف شده نشان می دهد برنامه ما انتظاراتی که که در قالب Test Case پیاده کردیم را براورده می کند. با این حال نمی توانیم تضمین کنیم برنامه ما بدون نقص است چرا که تست نرم افزار تنها وجود نقص ها را می تواند نشان دهد نه عدم وجود انها را. هر چقدر تست های مناسب تری طراحی کنیم و تلاش کنیم تا همه نقاط حساس برنامه را پوشش دهیم به تولید یک محصول با کیفیت نزدیک تر می شویم.

Unit Testing چگونه بر روند توسعه تاثیر میگذارد؟

داشتن Unit Testing برای پروژه علاوه بر نمایش نقص های موجود، در روند توسعه و توسعه تیمی هم نقش بسیار مهمی دارد؛ در نظر بگیرید که پروژه دارای یک سری امکانات از قبل پیاده سازی شده است و قرار است امکانات جدید به آن اضافه شود که ممکن است قسمت هایی ه پیش تر پیاده سازی شده است را تحت تاثیر قرار دهد، در نتیجه شما مجبور می شوید پروژه را دوباره از نو تست کنید در حالی که با داشتن Test Case هایی برای پیاده سازی های پیشین می توانید به سرعت مشکلات ایجاد شده در قسمت های قدیمی را تشخیص دهید. همچنین بعنوان برنامه نویس ارشد می توانید با داشتن Test Case های مناسب با پوشش کافی از صحت کد های نوشته شده توسط اعضای تیم اطمینان حاصل کنید.

چگونه باید Test Case بنویسیم؟

در این بخش می خواهیم مثالی از یک قطعه کد (بسیار ساده) و یک Test Case برای اون شرح دهیم. برای مثال قطعه کد زیر را در نظر بگیرید:

function calculate(int $a, int $b, string $op): int
{
    switch($op) {
        case "+":
            return $a + $b;
        case "-":
            return $a - $b;
        default:
            throw new InvalidOperationException();
    }
}

اکنون اگر بخواهیم برای این کد Test Case بنویسیم:

public function test_sum()
{
    $a = 6;
    $b = 7;
    $result = calculate($a, $b, "+");
    assertEquals(13, $result);
}

تابع assertEquals به بیان ساده بررسی می کند که آیا مقدار متغیر result برابر عدد ۱۳ هست یا نه و چنانچه برابر بود نتیجه تست (assertion) موفق و در غیر این صورت شکست است.

حال در نظر بگیرید شما یا هر برنامه نویس دیگری قصد دارید که کد بالا را توسعه دهید و عمل ضرب را به آن اضافه کنید، در این صورت Test Case بالا باز هم با موفقیت اجرا می شود اما اگر توسعه شما به کد پایین منجر شود:

function calculate(int $a, int $b, string $op): int
{
    switch($op) {
       case "+":
          return $a - $b;
       case "-":
          return $a - $b;
       case "*":
          return $a * $b;
       default:
          throw new InvalidOperationException();
    }
}

که تغییر ایجاد شده باعث شده قسمتی از کد قبلی هم به اشتباه عوض شود (علامت جمع به تفریق تبدیل شده)، جای نگرانی نیست چرا که اگر تست ها را قبل از انتشار اجرا کنید متوجه خواهید شد که تست مربوط به جمع Failed میشود پس کد شما دیگر بدرستی اعداد را جمع نمی کند. اما اگر اتفاق مشابه‌ای برای کد تفریق بیفتد ممکن است به این سادگی متوجه آن نشوید.

نتیجه گیری

در این پست توضیح دادیم که چگونه Unit Testing به توسعه ای راحت تر و مطمئن تر کمک می کند و اینکه چگونه باعث می شود محصولی با خطای کمتر تولید کنیم. در انتها در قالب یک مثال بسیار ساده شرح دادیم که چگونه Test Case طراحی کنیم و از آن در بررسی پروژه استفاده کنیم. توجه کنید که موارد شرح داده شده مقدمه ای بسیار کوتاه از دنیای بزرگ Testing است و در پست های بعدی درباره موارد پیشرفته تری که در تست یک نرم افزار با آنها رو به رو می شویم بیشتر توضیح خواهم داد.