Unit Testing چیست؟
Unit Testing اپلیکیشنهای نرمافزاری در خلال توسعه(کدنویسی) انجام میشود.
هدف Unit Testing، جداسازی بخشی از کد و ممیزی صحت آن است. در کدنویسی Procedural ممکن است Unit مد نظر ما یک Function یا Procedure باشد.
هدف Unit Testing، جداسازی هر بخش از برنامه و نمایش این موضوع است که هر بخش به صورت فردی درست کار میکند. Unit Testing معمولا توسط توسعهدهنده انجام میشود.
چرا Unit Testing را انجام میدهیم؟ چرا این کار مهم است؟
گاهی اوقات توسعهدهندگان نرمافزار برای صرفهجویی در زمان، حداقلِ Unit Testing را اِعمال میکنند. این یک افسانه نادرست است که این کار باعث صرفهجویی زمانی و مالی میشود، چرا که کاهش Unit Testing منجر به افزایش هزینههای مربوط به اصلاح نواقص در طول تست سیستم(System Testing)، تست یکپارچهسازی(Integration Testing) و حتی Beta Testing(یکی از شاخههای Acceptance Testing یا تست پذیرش) پس از تکمیل اپلیکیشن میشود. Unit Testing در طول مرحله توسعه انجام شده و در نهایت موجب صرفهجویی در زمان و هزینه مالی میشود.
چگونه Unit Test Caseها را ایجاد نماییم
Unit Testing معمولا یک عملیات اتوماتیک است، اما ممکن است هنوز به شکل دستی هم انجام شود. یک روش دستی برای Unit Testing ممکن است از یک سند آموزشی گام به گام استفاده کند.
اما تحت یک رویکرد اتوماتیک:
- یک توسعهدهنده میتواند صرفا برای تست Function، در اپلیکیشن کد تستی بنویسد. آنها بعدا روی آن اظهار نظر کرده و در نهایت هنگامیکه Application به درستی کار کرد کد تستی را حذف میکنند.
- آنها همچنین میتوانند Function را برای تست دقیقتر ایزوله(جداسازی) نمایند. این یک روش کاملتر برای Unit Testing است که شامل کپی کردن و قرار دادن Function در محیط تست ویژه(محیطی غیر از محیط معمول) است. جداسازی کد کمک میکند تا وابستگیهای غیرضروری بین کدِ تحت تست و سایر Unitها و یا فضاهای دادهای(Data) در محصول را فاش نمایید. پس از آن این وابستگیها میتوانند حذف شوند.
کدنویس ممکن است برای توسعه Test Caseهای اتوماتیک از Unit Test Framework استفاده کند. با استفاده از یک Automation Framework، توسعهدهنده به منظور ممیزی صحت Unit، معیارها(Criteria) را برای تست کردن، کد میکند. در حین اجرای Test Caseها، Framework، آن دست از مواردیکه هر کدام از معیارها را Fail کرده باشند را Log میکند. بسیاری از Frameworkها نیز به طور خودکار Test Caseهای Fail شده را Flag(مشخص کردن با علامت) کرده و به صورت خلاصه گزارش میدهند. بسته به شدت نارسایی(Failure)، ممکن است Framework، تستهای بعدی را متوقف(Halt) کند.
Mock Objectها
Unit Testing، بر Mock Objectهایی تکیه دارد که به منظور تست قسمتهایی ایجاد میشوند که هنوز بخشی از اپلیکیشنِ کامل نیستند. Mock Objectها قسمتهای گمشده برنامه را پر میکنند. به عنوان مثال، شما ممکن است یک Function داشته باشید که نیاز به متغیرها یا Objectهایی داشته باشد که هنوز ایجاد نشدهاند، و یا شما به آنها دسترسی ندارید. در Unit Testing، آنها را به صورت Mock Object ایجاد میکنند، که صرفا به منظور کمک به Unit Testing در آن بخش از کد اِعمال میشوند.
ابزار Unit Testing
ابزارهای اتوماتیکسازی زیادی برای کمک به Unit Testing وجود دارد. ما چند نمونه را در زیر ارائه خواهیم کرد:
- Jtest: ابزار Parasoft Jtest یک پلاگین IDE است که از Open-Source Frameworkها(Junit، Mockito، PowerMock و Spring) به همراه اقدامات هدایت شده و تککلیلکیِ ساده برای ایجاد، مقیاسگذاری، و نگهداشت Unit Testها بهره میبرد. با خودکارسازی این جنبههای وقتگیر در Unit Testing، توسعهدهنده برای تمرکز بر منطق Business و ایجاد Test Suiteهای پرمغزتر آزاد خواهد شد.
- Junit: ابزار Junit یک ابزار رایگان تست است که برای زبان برنامهنویسی Java استفاده میشود. این ابزار Assertionهایی را برای شناسایی Test Method ارائه میدهد.
- NUnit: ابزار NUnit پرطرفدارترین Unit-Testing Framework است که برای همه زبانهای Net. استفاده میشود. این ابزار Open Source بوده و اجازه میدهد اسکریپتها را به صورت دستی بنویسید. این ابزار از تستهای Data-Driven که میتوانند به صورت موازی اجرا شوند، پشتیبانی میکند.
- JMockit: ابزار JMockit یک ابزار Unit Testing به صورت Open-Source است. این ابزار یک Code Coverage Tool با متریکهای Line و Path است. این ابزار Mock کردن APIها را بواسطه Recording و Verification Syntax مقدور میسازد. بعلاوه این ابزار Path Coverage، Line Coverage، و Data Coverage را ارائه میدهد.
- EMMA: ابزار EMMA هم یک ابزار Open-Source برای تحلیل و گزارش کد نوشته شده در زبان جاواست. EMMA از انواع Coverageها مانند Method، Line، و Basic Block پشتیبانی میکند. این یک ابزار Java-Based است، بنابراین از External Dependencyها مستقل بوده و میتواند به Source Code دسترسی داشته باشد.
- PHPUnit: ابزار PHPUnit یک ابزار Unit Testing برای برنامهنویسان PHP است. این ابزار بخشهای کوچکی از کد را که یونیت نامیده میشوند را دریافت کرده، و هر یک را به صورت جداگانه تست میکند. این ابزار همچنین به توسعهدهندگان اجازه میدهد برای اثبات این موضوع که سیستم به طرز معینی رفتار میکند، از Assertion Methodهای از پیش تعریف شده استفاده نمایند.
اینها تنها چند نمونه از ابزارهای Unit Testing هستند. تعداد بیشتری از این ابزارها، مخصوصا برای زبانهای C و Java، وجود دارند. با این وجود، فارق از زبان برنامهنویسی، مطمئن باشید ابزاری را که نیاز برنامهنویسی شما در حوزه Unit Testing را برطرف کند، خواهید یافت.
Extreme Programming-XP و Unit Testing
Unit Testing در Extreme Programming شامل استفاده گسترده از Testing Frameworkها میشود. یک Unit Testing Framework به منظور ایجاد Unit Testهای اتوماتیک استفاده میشود. Unit Testing Frameworkها منحصر به XP نیستند، اما برای آن ضروری هستند. در زیر به برخی از مواردی که XP برای دنیای Unit Testing به ارمغان آورده است اشاره میکنیم:
- تستها قبل از کد نوشته شود
- تکیه شدید روی Testing Frameworkها
- همه کلاسها در اپلیکیشنها تست میشوند
- Integration سریع و آسان امکان پذیر است
افسانه Unit Testing
افسانه: این کار نیازمند زمان است، و من همیشه از زمانبندی عقبم
کد من محکم است! من به Unit Testها نیاز ندارم
طبیعت افسانهها مفروضات دروغین است. فرضایتی که مطرح شد منجر به ایجاد یک چرخه نادرست به شرح زیر میشود:
حقیقت Unit Testing افزایش سرعت در توسعه است.
برنامه نویسان فکر میکنند که تست Integration تمام خطاها را استخراج میکند، و به همین دلیل تست یونیت را اجرا نمیکنند. هنگامی که Unitها یکپارچه میشوند، خطاهای بسیار سادهای که میتوانند به راحتی در یونیتِ تست شده، پیدا و رفع شوند، زمان زیادی را برای Trace و رفع، صرف میکنند.
مزایای Unit Testing
- توسعهدهندگانی که به دنبال بدست آوردن Functionalityهای ارائه شده توسط یک Unit و نحوه استفاده از آن هستند، میتوانند Unit Testing را به عنوان اهرمی برای به دست آوردن درک اولیه از Unit API در نظر بگیرند.
- Unit Testing به برنامهنویس اجازه میدهد کد خود را بعدا Refactor نماید، و مطمئن شود که ماژول همچنان درست کار میکند(مانند تست رگرسیون). این رویه برای نوشتن Test Caseها برای تمام Functionها و Methodهاست تا هر زمان که یک تغییر سبب بروز یک Fault(عیب) شد، بتوان آنرا به سرعت شناسایی و رفع نمود.
- با توجه به ماهیت ماژولار در Unit Testing، میتوانیم بخشهایی از پروژه را بدون انتظار برای تکمیل دیگر قسمتها تست کنیم.
محدودیتهای Unit Testing
- از Unit Testing نمیتوان انتظار داشت که تمام خطاهای اپلیکیشن را استخراج نماید. امکانسنجی تمام مسیرهای اجرایی حتی در برنامههای کم اهمیت هم امکان پذیر نیست
- Unit Testing با توجه به ماهیت خود، بر روی یک Unit از کد تمرکز میکند. از این رو نمیتواند خطاهای Integration یا خطاهای سیستم را استخراج نماید
پیشنهاد میشود که Unit Testing به صورت پیوسته با سایر فعالیتهای تست مورد استفاده قرار گیرد.
تکنیک های Unit Testing
- تکنیکهای ساختاری(Structural)
- تکنیکهای تست کارکردی(Functional)
- تکنیکهای مبتنی بر خطا(Error Based)
بهترین شیوههای Unit Testing
- Unit Test Caseها باید مستقل باشند. در مورد هر افزایش یا تغییر در نیازمندیها(Requirement)، نباید Unit Test Caseها تحت تاثیر قرار گیرند
- در هر لحظه فقط یک کد را تست کنید
- دستورالعملهای نامگذاری واضح و نامتناقض را برای Unit Testها دنبال کنید
- در صورت تغییر در کد هر ماژول، اطمینان حاصل کنید که یک Unit Test Case متناظر برای ماژول وجود دارد، و ماژول مذبور قبل از تغییر در پیادهسازی، تستها را Pass میکند
- باگهای شناسایی شده در طول Unit Testing باید قبل از عزیمت به فاز بعدی در SDLC رفع شوند
- رویکر “Test as You Code”(همینطور که کد میزنید، تست کنید) را اتخاذ کنید. نوشتن کد زیاد و بدون تست به معنی مسیرهای بیشتریست که باید برای کشف خطاها بررسی شوند
خلاصه
همانطور که میبینید، ممکن است Unit Testing درگیری زیادی را برای شما به ارمغان آورد. Unit Testing بسته به اپلیکیشن تحت تست و استراتژیهای تست، ابزار و فلسفههای مورد استفاده، میتواند پیچیده یا نسبتا ساده باشد.
این مطلب بخشی از دوره آموزشی رایگان تست نرمافزار بود، که میتوانید تمامی مطالب این دوره رایگان را در اینجا مشاهده نمایید.
بسیار عالی
ممنون