صادق خانزادی
صادق خانزادی
خواندن ۱۰ دقیقه·۳ روز پیش

using JUnit5 and Mockito (مفاهیم کلی تست)

یه مجموعه آموزش داریم تحت عنوان using JUnit5 and Mockito که اومدیم توی چنتا سرفصل تقسیمش کردیم .

این آموزش به دو بخش تقسیم شده مفاهیم کلی تست و مثال ها و انوتیشن ها mocito و junit5 .

این آموزش رو با توضیحات حوصله سربر انواع تست و کلیات شروع میکنیم و برای ادامه به آموزش مثال ها و انوتیشن ها mocito و junit5 برید و با قدرت ادامه بدید.



انواع تست در مهندسی نرم افزار

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

  • تست‌های واحد (Unit Testing)
  • تست‌های یکپارچگی (Integration Testing)
  • تست‌های سیستم (System Testing)
  • تست‌های پذیرش (Acceptance Testing)
  • تست‌های رابط کاربری (UI Testing)
  • تست‌های امنیتی (Security Testing)
  • تست‌های عملکردی (Performance Testing)
  • تست‌های استرس (Stress Testing)
  • تست‌های رگرسیونی (Regression Testing)
  • تست‌های قابلیتشناسی (Usability Testing)
  • یه موارد هم مثل TDD , BDD , ATDD , ... داریم که مختصر یه توضیح میدم




تست‌های واحد (Unit Testing) : ما با این کار داریم

توضیح:

تست واحد، پایه‌ای‌ترین نوع تست است که به بررسی یک واحد کوچک از برنامه (معمولاً یک متد یا کلاس) می‌پردازد. هدف این است که مطمئن شویم هر واحد به درستی و مطابق با انتظار عمل می‌کند.

ویژگی‌ها:

  • محدوده تست: یک بخش کوچک از کد، مانند یک متد.
  • ابزارهای متداول: JUnit (برای جاوا)
  • هدف: شبیه‌سازی شرایط مختلف و بررسی اینکه آیا کد تحت شرایط مختلف به درستی عمل می‌کند یا خیر.

مثال:

فرض کنید یک متد add در کلاسی به نام calculator داریم. تست واحد این متد بررسی می‌کند که آیا جمع دو عدد به درستی انجام می‌شود یا نه.

تست‌های یکپارچگی (Integration Testing)

توضیح:

تست‌های یکپارچگی برای بررسی تعاملات بین چند واحد مختلف (کلاس‌ها یا ماژول‌ها) به کار می‌روند. این تست‌ها به شما کمک می‌کنند که مطمئن شوید اجزای مختلف سیستم به درستی با هم کار می‌کنند.

ویژگی‌ها:

  • محدوده تست: چند واحد یا ماژول که با هم تعامل دارند.
  • ابزارهای متداول: JUnit, TestNG، و ابزارهای خاص مانند Spring Test برای فریم‌ورک‌های مبتنی بر Spring.
  • هدف: بررسی اینکه آیا تعاملات بین اجزای مختلف (مانند پایگاه داده، سرویس‌ها، APIها) به درستی کار می‌کنند یا خیر.

مثال:

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

ما الان توی پروژه ای که داریم برای تست یه docker به صورتی اتومات کانفیگ شده که با استارت کردن یه تست ، container های داکر جهت تست اجرا میشن (redis , mysql , ...) و بعد از پایان هر متد تست ، بسته به کانفیگمون container ها بسته و container های جدید اجرا میشن.

تست‌های سیستم (System Testing)

توضیح:

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

ویژگی‌ها:

  • محدوده تست: کل سیستم نرم‌افزاری که شامل تمام اجزا و زیرسیستم‌ها می‌شود.
  • ابزارهای متداول: تست‌های دستی یا خودکار با استفاده از ابزارهایی مانند Selenium، JMeter و یه سری از شرکت ها پول ندارن تستر بگیرن یه تعداد نفر رو گذاشتن با postman سرویس هارو کال میکنن .
  • هدف: ارزیابی عملکرد کلی سیستم از نظر عملکرد، امنیت، و تطابق با نیازمندی‌ها.

مثال:

در تست سیستم ممکن است تست کنید که آیا تمامی ویژگی‌های اپلیکیشن وب، از جمله ثبت‌نام کاربر، جستجو، و پرداخت، به درستی و بدون اشکال کار می‌کنند یا خیر.

تست‌های پذیرش (Acceptance Testing)

توضیح:

تست پذیرش بررسی می‌کند که آیا نرم‌افزار یا ویژگی خاص مطابق با نیازمندی‌های تجاری و خواسته‌های کاربر نهایی عمل می‌کند یا خیر. این نوع تست معمولاً توسط تیم‌های QA یا حتی خود مشتری انجام می‌شود.

ویژگی‌ها:

  • محدوده تست: ارزیابی تطابق نرم‌افزار با نیازمندی‌ها و خواسته‌های کاربر.
  • ابزارهای متداول: Cucumber، FitNesse، SpecFlow (برای BDD).
  • هدف: اطمینان از اینکه نرم‌افزار تمام نیازهای تجاری و عملکردی را برآورده می‌کند.

مثال:

اگر پروژه‌ای برای فروش آنلاین محصولات انجام داده‌اید، تست پذیرش می‌تواند شامل بررسی این باشد که آیا مشتری می‌تواند به درستی محصولی را جستجو ، آن را به سبد خرید اضافه کند و پرداخت را انجام دهد.

تست‌های رابط کاربری (UI Testing)

توضیح:

تست‌های رابط کاربری به بررسی تعاملات کاربر با اپلیکیشن می‌پردازند. این تست‌ها به شما کمک می‌کنند تا اطمینان حاصل کنید که رابط کاربری (UI) به درستی و طبق انتظارات کاربر عمل می‌کند.

ویژگی‌ها:

  • محدوده تست: قسمت‌هایی از سیستم که مستقیماً با کاربر تعامل دارند (مانند فرم‌ها، دکمه‌ها، منوها).
  • ابزارهای متداول: Selenium, Appium, Cypress.
  • هدف: بررسی درست بودن نمایش و عملکرد رابط کاربری در شرایط مختلف.

مثال:

تست UI می‌تواند شامل بررسی این باشد که آیا فرم ثبت‌نام به درستی نمایش داده می‌شود و کاربر می‌تواند بدون هیچ مشکلی فرم را پر کند و ارسال کند.

تست‌های امنیتی (Security Testing)

توضیح:

تست‌های امنیتی به بررسی آسیب‌پذیری‌های نرم‌افزار و تهدیدات امنیتی می‌پردازند. این تست‌ها به‌ویژه در اپلیکیشن‌های حساس و سیستم‌هایی که داده‌های حساس را پردازش می‌کنند، اهمیت دارند.

ویژگی‌ها:

  • محدوده تست: آسیب‌پذیری‌های امنیتی مانند SQL Injection، حملات XSS، حملات CSRF و سایر تهدیدات.
  • ابزارهای متداول: OWASP ZAP, Burp Suite.
  • هدف: ارزیابی امنیت سیستم و پیدا کردن آسیب‌پذیری‌های ممکن.

مثال:

  • تست امنیتی ممکن است شامل بررسی این باشد که آیا یک فرم ورودی در وب‌سایت در برابر حملات SQL Injection محافظت شده است یا خیر.

تست‌های عملکردی (Performance Testing)

توضیح:

تست‌های عملکردی برای ارزیابی عملکرد سیستم تحت شرایط مختلف، مانند بار زیاد یا استفاده طولانی‌مدت، انجام می‌شوند. این تست‌ها به شما کمک می‌کنند تا مطمئن شوید که سیستم توانایی مدیریت بار و عملکرد مطلوب را دارد.

ویژگی‌ها:

  • محدوده تست: عملکرد کلی سیستم مانند زمان پاسخگویی، مصرف منابع، و مقیاس‌پذیری.
  • ابزارهای متداول: JMeter, Gatling, LoadRunner.
  • هدف: بررسی اینکه آیا سیستم تحت فشارهای مختلف قادر به حفظ عملکرد خود است یا خیر.

مثال:

تست عملکردی می‌تواند شامل بررسی این باشد که آیا وب‌سایت قادر به مدیریت 1000 کاربر همزمان بدون کاهش سرعت یا خرابی است یا خیر.

تست‌های استرس (Stress Testing)

توضیح:

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

ویژگی‌ها:

  • محدوده تست: بار غیرمعمول و شرایط فشار بالا.
  • ابزارهای متداول: JMeter, LoadRunner.
  • هدف: شبیه‌سازی شرایط بحرانی و بررسی اینکه آیا سیستم می‌تواند عملکرد خود را حفظ کند یا خیر.

مثال:

تست استرس ممکن است شامل شبیه‌سازی تعداد بسیار زیادی درخواست همزمان به یک وب‌سایت باشد تا عملکرد آن تحت فشار شدید بررسی

تست‌های رگرسیونی (Regression Testing)

توضیح:

تست رگرسیونی به بررسی این می‌پردازد که آیا تغییرات جدید در کد باعث ایجاد مشکلات یا خرابی در بخش‌های قبلی نرم‌افزار شده است یا خیر.

ویژگی‌ها:

  • محدوده تست: بررسی تاثیر تغییرات جدید بر بخش‌های مختلف نرم‌افزار.
  • ابزارهای متداول: JUnit، Selenium.
  • هدف: اطمینان از اینکه هیچ یک از ویژگی‌های موجود تحت تاثیر تغییرات جدید قرار نگرفته است.

مثال:

اگر به کد یک اپلیکیشن تغییراتی اضافه کنید، تست رگرسیونی بررسی می‌کند که آیا ویژگی‌های قدیمی مانند ورود به سیستم یا ارسال ایمیل‌ها هنوز به درستی کار می‌کنند یا خیر.

تست‌های قابلیتشناسی (Usability Testing)

توضیح:

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

ویژگی‌ها:

  • محدوده تست: بررسی تجربه کاربری و قابلیت استفاده.
  • ابزارهای متداول: تست‌های دستی یا خودکار.
  • هدف: اطمینان از اینکه رابط کاربری و تجربه کاربری بهینه هستند.



حالا بگیم که BDD , TDD , ATDD چیه

توسعه نرم‌افزار تحت مفهومی به نام «توسعه مبتنی بر تست» (Test-Driven Development) و «توسعه مبتنی بر رفتار» (Behavior-Driven Development) می‌تواند به تضمین کیفیت نرم‌افزار کمک کند. علاوه بر این دو، روش‌های دیگری نیز وجود دارند که می‌توانند در فرآیند توسعه نرم‌افزار مورد استفاده قرار گیرند. (من همین سه مورد رو بلد بودم ممکنه موارد دیگه هم وجود داشته باشه پس خودتون سرچ بزنید)

Test-Driven Development (TDD)

تعریف

یک روش توسعه نرم‌افزار است که بر اساس نوشتن تست‌های خودکار قبل از نوشتن کد اصلی تاکید دارد. فرآیند معمول TDD شامل مراحل زیر است:

  1. نوشتن تست جدید: ابتدا یک تست کوچک و خاص برای عملکردی که قصد اضافه کردن آن به نرم‌افزار را دارید، بنویسید. این تست باید در ابتدا رد شود چون هنوز کدی برای آن ویژگی نوشته نشده است.
  2. نوشتن کد: اکنون کدی بنویسید که تست را پاس کند. در این مرحله تمرکز باید فقط بر پاس کردن تست باشد و نه بهینه‌سازی.
  3. بازبینی کد (Refactor): بهبود کد برای اطمینان از بهینه بودن آن از نظر عملکرد و خوانایی، بدون تغییر رفتار آن.
  4. تکرار مراحل: این چرخه برای هر ویژگی جدید یا رفع باگ تکرار می‌شود.

مزایا

  • اطمینان از کار کردن صحیح ویژگی‌های نرم‌افزار از ابتدا.
  • تشویق به طراحی مناسب و ماژولار.
  • مستندسازی خودکار ویژگی‌ها و کد.

Behavior-Driven Development (BDD)

تعریف

تکامل یافته TDD است که بر رفتار نرم‌افزار از دید کاربر تمرکز می‌کند. در این روش، تست‌ها به شکل قابل درک و فهم برای همه اعضای تیم ، از جمله توسعه‌دهندگان، تست‌کنندگان، و مدیران پروژه نوشته میشه .

فرآیند

بر اساس یه سناریو معمولا پیش میره که چنتا step میتونه داشته باشه ، که معمولاً یه قالب کلی داره :

  • Given:

شرایط اولیه یا پیش‌نیازهایی که باید قبل از اجرای رفتار مهیا شوند.

  • When:

اتفاق یا عملی که برای بررسی رفتار رخ می‌دهد.

  • Then:

نتیجه‌ای که پس از وقوع عمل انتظار می‌رود.

مزایا

  • ایجاد ارتباط بهتر بین تمام اعضای پروژه .
  • مشخص کردن دقیق رفتار مورد انتظار سیستم.

Acceptance Test-Driven Development (ATDD)

مشابه BDD، اما تمرکز بیشتری بر پذیرش کلی نرم‌افزار دارد. در این روش، تست‌های قبل از توسعه ویژگی‌ها نوشته می‌شوند و دیدگاه تمام اعضای یک پروژه را منعکس می‌کنند.



مفهوم MOCK : (توی آموزش بعدی کدش رو میزاریم)

حالا mock چیه : Mocking یا شبیه‌سازی یکی از مفاهیم مهم در تست‌نویسی است که به شما کمک می‌کند برای بخش‌هایی از سیستم که نمی‌خواهید در تست‌ها به طور واقعی اجرا شوند، نسخه‌های جعلی (mock) ایجاد کنید. این کار برای تست‌های واحد (Unit Testing) و تست‌های یکپارچگی (Integration Testing) ضروری است، به‌خصوص زمانی که بخش‌هایی از سیستم وابستگی به منابع خارجی مانند پایگاه‌داده‌ها، APIها، یا سرویس‌های دیگر دارند.

چرا نیاز به Mocking داریم؟

در تست‌نویسی، معمولاً نمی‌خواهیم تمام اجزای سیستم را در یک زمان تست کنیم، زیرا این کار می‌تواند تست را پیچیده و زمان‌بر کند. به علاوه، ممکن است در برخی شرایط مانند:

  1. وابستگی به پایگاه‌داده‌ها (که ممکن است داده‌ها در آن تغییر کنند یا دسترسی به آن دشوار باشد).
  2. فراخوانی سرویس‌های خارجی (APIها یا وب‌سرویس‌ها) که سرعت یا هزینه زیادی دارند.
  3. نیاز به شبیه‌سازی رفتارهایی که به سختی می‌توان آن‌ها را تحت کنترل قرار داد (مثلاً زمانی که یک سرویس از بیرون خطا می‌دهد).

در چنین مواردی، می‌توانیم از Mocking استفاده کنیم تا تنها بخش‌های موردنظر سیستم را تست کنیم و رفتار سایر بخش‌ها را شبیه‌سازی نماییم.

1. ابزارهای Mocking در جاوا

در جاوا، چندین کتابخانه برای mocking وجود دارد که از رایج‌ترین آن‌ها می‌توان به Mockito و EasyMock اشاره کرد. در اینجا به توضیح مختصر از Mockito می‌پردازیم که یکی از محبوب‌ترین ابزارهای mocking است.

1.1. Mockito

یک فریم‌ورک برای ایجاد mocks، stubs و spies است که به شما کمک می‌کند تا وابستگی‌های خارجی را شبیه‌سازی کرده و فقط بخشی از سیستم را که مورد نظر دارید، تست کنید.

1.2. ایجاد Mock با Mockito

بیاید یه مثال بزنیم ، فرض کنید که کلاسی به نام DatabaseService داریم که وابستگی به یک پایگاه‌داده دارد. می‌خواهیم هنگام نوشتن تست‌ها از پایگاه‌داده واقعی استفاده نکنیم، بنابراین از mocking استفاده می‌کنیم.

1.3. Mockito رفتارهای پیچیده‌تر

همچنین می‌توانید رفتارهای پیچیده‌تری مانند پرتاب استثنا (throwing exceptions)، شمارش تعداد فراخوانی‌ها، یا بررسی مقدارهای بازگشتی در mock را شبیه‌سازی کنید.

1.4. استفاده از پایگاه‌داده In-Memory (برای ماک کردن پایگاه داده)

یکی از روش‌های رایج برای انجام تست‌های پایگاه‌داده بدون نیاز به پایگاه‌داده واقعی، استفاده از In-memory database است. پایگاه‌داده‌هایی مانند H2، HSQLDB و Derby می‌توانند در حافظه اجرا شوند و داده‌ها را بدون نیاز به ذخیره‌سازی بر روی دیسک نگهداری کنند.

هم میشه از mockito استفاده کرد هم میشه از SpringDataJpa برای تستهامون استفاده کنیم.


برای ادامه مباحث تست به آموزش Junit و Mockito برید اونجا با مثال های کابردی انواع حالت های مختلف که بهش بر میخورید رو تست کردیم.

موفق و پیروز باشید .
اگر موردی به ذهنتون رسید که کم بود بگید اضافه کنم.

تستjunitjavaspring boot
Java Developer - Technical Team Lead At Dotin
شاید از این پست‌ها خوشتان بیاید