طبق تعریف ویکیپدیا، Unit Testing سازوکاری به منظور آزمودن صحتِ کارکرد بلوکهای کوچکی از سورسکد نرمافزار است که بر آن اساس کارکرد صحیح هر قسمت از کد ارزیابی میگردد که تحت عنوان Unit یا «واحد» شناخته میشوند.
نکتهای که در ارتباط با Unit Test حائز اهمیت است اینکه در این مدل از تست نرمافزار تحت هیچ عنوان یک ماژول یا کامپوننت کامل از اپلیکیشن تست نمیشود و یا آنچه کاربر از خروجی نرمافزارمان میبیند در این پروسهٔ مد نظر قرار داده نخواهد شد بلکه همانطور که پیش از این اشاره کردیم، کوچکترین واحدهای سورسکد که تَسک خاصی را انجام میدهند یا چیزی را ریترن میکنند مورد آزمایش قرار خواهد گرفت.
به طور مثال، میتوان یک کلاس را در نظر گرفت که بر اساس قانون Single Responsibility توسعه یافته و بالتبع صرفاً یک کار خاص را انجام میدهد به طوری که با استفاده از Unit Test میتوانیم بسنجیم ببینیم که آیا آن کار را به درستی انجام میدهد یا خیر که اگر پاسخ به این پرسش مثبت باشد، میگوییم که کلاس مذکور تست را Pass کرده است و در غیر این صورت Fail شده است. در واقع، در برنامهنویسی شیئگرا (OOP) تکتک متدهای قرار گرفته داخل بدنهٔ کلاس به منزلهٔ یونیت یا واحد هستند که میتوان آنها را به صورت مجزا مورد آزمایش قرار داده از کارکرد صحیح آنها اطمینان حاصل کرد.
همانطور که در تصویر زیر ملاحظه میشود، Unit Testing به عنوان اولین سطح از تست نرمافزار شناخته میشود که معمولاً توسط خود توسعهدهندگان نرمافزار عملی میگردد:
در لایهٔ بعد، Integration Testing را داریم که عبارت است از ادغام بلوکهای کوچک کد با یکدیگر و تشکیل یکسری ماژول سپس ادغام چندین ماژول با یکدیگر و تست عملکرد کلی آنها به طوری که در نهایت این اطمینان حاصل میشود که کامپوننتها و یا ماژولهایی که توسط دولوپرهای مختلف در یک تیم نرمافزاری توسعه داده میشوند به درستی با یکدیگر ارتباط برقرار میکنند.
در لایهٔ بعد از تست نرمافزار به System Testing میرسیم که به موجب آن یک نرمافزار یا اپلیکیشن کامل تحت بررسی قرار میگیرد به طوری که این موضوع بررسی خواهد شد که آیا نرمافزارمان وقتی در اختیار کاربرانش قرار گیرد به درستی کار خواهد کرد و نیازهای آنها را مرتفع خواهد ساخت یا خیر.
و در نهایت به Acceptance Testing میرسیم که در این مرحله از تست نرمافزار مشخص میشود که آیا اساساً نرمافزاری که توسعه دادهایم نیاز/نیازهای کاربران را همانطور که آنها انتظار دارند برآورده میسازد یا خیر. به عبارتی، این نوع تست مشخص میسازد که آیا تطابقی مابین انتظارات کاربران از نرمافزار با آنچه واقعاً نرمافزار در اختیارشان قرار میدهد وجود دارد یا خیر.
درآمدی بر مزایای Unit Test
در فضای توسعهٔ نرمافزار کنونی که نیازها دائماً در حال تغییر هستند و تیمهای مهندسی نیز با تغییر در کدهای قدیمی و یا افزودن فیچرهای جدید به این نیازها پاسخ میدهند، همواره این نیاز احساس میگردد تا به سازوکاری اندیشید تا عرضهٔ نسخههای جدید با حداقل مشکلات و باگهای نرمافزاری در اختیار کاربران قرار گیرد و اینجا است که Unit Test عرض اندام میکند. در همین راستا، در ادامه برخی مزایایی را برخواهیم شمرد که این نوع تست برای دولوپرها به ارمغان خواهد آورد:
- یونیت تست باعث میگردد تا دولوپرها با اعتمادبهنفس بیشتری اقدام به دیپلوی نسخههای جدید نرمافزار روی سرور کنند.
- برای انجام یونیت تست، سورسکد میباید ماژولار باشد و همین مسئله باعث میگردد تا بتوان سورسکد را بازاستفاده نمود.
- گرچه تستنویسی مستلزم صرف زمان است، اما باگهایی که با اجرای یونیت تستهای مختلف در مراحل توسعهٔ نرمافزار پیش از عرضهٔ آن به کاربران مشخص میشوند منجر به کاهش زمان دیباگینگ در مراحل آتی توسعه خواهند شد.
- هزینهٔ دیباگینگ با استفاده از یونیت تست به مراتب کمتر از یافتن باگها در مراحل آتی توسعهٔ نرمافزار است.
- پروسهٔ دیباگینگ با استفاده از یونیت تست به مراتب راحتتر خواهد شد چرا که در این صورت صرفاً نیاز است تا آخرین کدهای نوشتهشده را تحت بررسی قرار داد.
درآمدی بر معایب Unit Test
گرچه برخی مزایایی که در بالا بدانها اشاره کردیم به سادگی میتوانند ما را به عنوان یک توسعهدهنده مجاب کنند تا شروع به استفاده از یونیت تست کنیم، اما در عین حال یکسری نقاط ضعف نیز در ارتباط با این موضوع وجود دارند که برخی از مهمترین آنها عبارتند از:
- یونیت تست هرگز تمامی ارورهای نرمافزار را نخواهد یافت.
- یونیت تست روی بلوکهای کوچکی از سورسکد متمرکز است و از همین روی نمیتواند وقتی این بلوکهای کوچک با یکدیگر ادغام شدند مشکلات احتمالی آنها را بیابد.
نکاتی در ارتباط با Unit Test که میباید مد نظر قرار داد
در ارتباط با یونیت تست همواره یکسری Best Practice وجود دارد که چنانچه در فرآیند توسعهٔ نرمافزار مد نظر قرار داده شوند، خروجی کار به مراتب بهتر خواهد بود که برخی از مهمترین آنها عبارتند از:
- الزاماً نیازی به نوشتن تست برای تمامی بخشهای نرمافزار وجود ندارد؛ بلکه نیاز است تا روی فانکشنهایی تمرکز کرد که رفتار کلی سیستم ارتباطی تنگاتنگی با آنها دارا است.
- دیتایی که در پروسهٔ Unit Testing مورد استفاده قرار میگیرد میباید تا حد ممکن نزدیک به دیتای واقعی باشد.
- تستها میباید از یکدیگر مجزا باشند و در آنِ واحد فقط و فقط یک فانکشن تست گردد.
- به محض تغییر در سورسکد، میباید یونیت تست مربوطه را اجرا کرد تا از پاس شدن آن اطمینان حاصل کنیم.
- نامگذاری تستها میباید مرتبط با نامهای انتخابی برای کلاسهای اصلی باشد.
- در مواردی که از دستورات شرطی استفاده شده است، میباید تمامی حالات مد نظر قرار داده شوند.
- تستهایی که مینویسیم نیز میباید در سیستم ورژن کنترلی همچون گیت ثبت گردند.
جمعبندی
به طور خلاصه، میتوان گفت که هدف از Unit Test آن است که سورسکد نرمافزار را در قالب واحدهای کوچکی در نظر گرفته که هر کدام کار خاصی را انجام میدهند؛ سپس این موضوع سنجیده خواهد شد که آیا تکتک واحدها کارشان را به درستی انجام میدهند یا خیر.