Mockito — چیست، مفاهیم کلیدی و اصل کار

نویسنده: IT Sectr منتشر شده: 2026-04-08 زمان مطالعه: 8 دقیقه

Mockito یک فریم‌ورک متن‌باز برای ایجاد اشیاء mock در تست‌های واحد Java و Kotlin است که به شما امکان می‌دهد کد تست‌شونده را از وابستگی‌های خارجی جدا کنید. با کمک آن، توسعه‌دهنده مخازن واقعی، کلاینت‌های API و پایگاه‌های داده را با اشیاء جعلی کنترل‌شده با رفتار مشخص جایگزین می‌کند. به گزارش Mockito.org، این کتابخانه در بیش از 60% پروژه‌های Java که تست واحد انجام می‌دهند استفاده می‌شود.

نکات اصلی

  • Mockito — کتابخانه‌ای برای ایجاد اشیاء mock که وابستگی‌های واقعی را در تست‌ها جایگزین می‌کنند.
  • Mock — یک شیء جعلی که رفتار کامپوننت واقعی را شبیه‌سازی می‌کند.
  • Stubbing — تنظیم مقدار بازگشتی هنگام فراخوانی متد mock.
  • Verify — بررسی اینکه متد با آرگومان‌های مشخصی فراخوانی شده است.
  • @InjectMocks — تزریق خودکار وابستگی‌های mock به شیء تحت تست.

Mockito چیست؟

Mockito یک کتابخانه متن‌باز برای ایجاد اشیاء mock (جعلی) در تست‌های واحد در Java، Kotlin و دیگر زبان‌های JVM است. برخلاف JUnit که مسئول اجرای تست‌هاست، Mockito مشکل جداسازی را حل می‌کند — وابستگی‌های واقعی کلاس تحت تست را با اشیاء قابل پیش‌بینی جایگزین می‌کند.

بدون mockها، تست کردن متدی که به پایگاه داده یا API خارجی دسترسی دارد نیاز به راه‌اندازی محیط واقعی — استقرار DB، راه‌اندازی سرور — دارد. Mockito این وابستگی‌ها را با اشیاء با رفتار ثابت جایگزین می‌کند: متد repository.findById(1) همیشه یک شیء User مشخص را بدون مراجعه به پایگاه داده برمی‌گرداند.

معماری Mockito بر اساس الگوی Proxy (برای اینترفیس‌ها و کلاس‌ها) است. کتابخانه یک زیرکلاس یا پراکسی برای نوع مشخص شده تولید می‌کند و تمام فراخوانی‌های متد را رهگیری می‌کند و مقادیر پیش‌فرض یا مقادیر تعیین‌شده از طریق when().thenReturn() را برمی‌گرداند.

Mockito چگونه کار می‌کند

اصل کار Mockito بر سه عملیات پایه استوار است: ایجاد mock، تنظیم رفتار (stubbing) و بررسی فراخوانی‌ها (verification). هر عملیات از متدهای استاتیک کلاس org.mockito.Mockito استفاده می‌کند — پراستفاده‌ترین کلاس در اکوسیستم Java طبق آمار Maven Central. تمام فراخوانی‌های متدهای mock در حافظه ثبت می‌شوند که امکان بررسی بعدی آنها را از طریق verify فراهم می‌کند.

سه مرحله تست با Mockito

یک تست معمولی با Mockito از سه فاز تشکیل شده است: Arrange — ایجاد mockها و تنظیم stubها از طریق when().thenReturn()، Act — فراخوانی متد تحت تست، Assert — بررسی نتیجه از طریق assertEquals و verify(mock). این رویکرد AAA (Arrange-Act-Assert) نامیده می‌شود.

مثال پایه با mock مخزن

یک تست ساده را در نظر بگیرید که در آن Mockito مخزن کاربران را جایگزین می‌کند. متد when().thenReturn() mock را طوری تنظیم می‌کند که فراخوانی findById یک شیء User از پیش آماده‌شده را برگرداند.

java
// یک mock از مخزن ایجاد می‌کنیم
UserRepository mockRepo = mock(UserRepository.class);

// رفتار را تنظیم می‌کنیم: در findById(1) کاربر را برگردان
when(mockRepo.findById(1)).thenReturn(new User("Alice"));

// بررسی می‌کنیم که متد واقعاً فراخوانی شده است
User result = mockRepo.findById(1);
assertEquals("Alice", result.getName());
verify(mockRepo).findById(1);

ایجاد اشیاء mock

Mockito دو روش برای ایجاد mock ارائه می‌دهد: متد استاتیک mock(Class) و annotation @Mock با مقداردهی اولیه از طریق MockitoAnnotations.openMocks(). روش اول برای یک یا دو mock جمع‌وجور است، روش دوم زمانی که وابستگی‌ها زیاد است راحت‌تر است — annotations کد تکراری را کاهش می‌دهند.

از طریق متد استاتیک mock()

متد mock() یک کلاس دریافت می‌کند و یک شیء جعلی برمی‌گرداند که می‌تواند از طریق when().thenReturn() تنظیم شود. تمام متدهای تنظیم‌نشده مقادیر پیش‌فرض برمی‌گردانند: 0 برای اعداد، false برای boolean، null برای اشیاء.

java
ApiClient apiClient = mock(ApiClient.class);
Database database = mock(Database.class);

از طریق annotation @Mock با JUnit 5

annotation @Mock به همراه @ExtendWith(MockitoExtension.class) به طور خودکار برای تمام فیلدهای کلاس تست mock ایجاد می‌کند. افزونه MockitoExtension مسئول مقداردهی اولیه قبل از هر تست است.

java
@ExtendWith(MockitoExtension.class)
class UserServiceTest {

    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService;

    @Test
    void getUserShouldReturnUserFromRepo() {
        when(userRepository.findById(1)).thenReturn(new User("Alice"));
        User result = userService.getUser(1);
        assertEquals("Alice", result.getName());
    }
}

Stubbing: تنظیم رفتار mock

Stubbing — فرآیند تعیین اینکه متد mock در هنگام فراخوانی با آرگومان‌های مشخص چه چیزی را برگرداند. نحو پایه: when(mock.method(args)).thenReturn(value). برای سناریوهای مختلف، Mockito چندین نوع متد then ارائه می‌دهد.

متدهدف
thenReturn(value)همیشه مقدار مشخص شده را برمی‌گرداند
thenThrow(exception)هنگام فراخوانی استثنا پرتاب می‌کند
thenAnswer(answer)مقدار بازگشتی را به صورت پویا محاسبه می‌کند
thenCallRealMethod()متد واقعی را فراخوانی می‌کند (mock جزئی)

پاسخ پویا از طریق thenAnswer

زمانی که مقدار بازگشتی به آرگومان‌های فراخوانی بستگی دارد، از thenAnswer با لامبدا استفاده می‌شود. این برای شبیه‌سازی کار با داده‌های واقعی مفید است — مثلاً تولید ID بر اساس شیء ارسال‌شده.

java
when(repository.save(any())).thenAnswer(invocation -> {
    User user = invocation.getArgument(0);
    user.setId(42);
    return user;
});

Verify: بررسی تعاملات با mock

Verify یک قابلیت منحصربه‌فرد Mockito است که کتابخانه‌های قدیمی‌تر اشیاء mock (EasyMock, jMock) ارائه نمی‌دهند.

Verify تست‌ها را قابل‌اعتمادتر می‌کند، زیرا نه تنها مقدار بازگشتی، بلکه اثرات جانبی — فراخوانی متدهایی که نتیجه برنمی‌گردانند (متدهای void) — را بررسی می‌کند. متد verify(mock).methodName(args) بررسی می‌کند که آیا متد مشخصی از mock با آرگومان‌های داده‌شده فراخوانی شده است. این امکان تست نه تنها نتیجه، بلکه فرآیند — واقعیت مراجعه به وابستگی — را فراهم می‌کند.

بررسی تعداد فراخوانی‌ها

به طور پیش‌فرض verify بررسی می‌کند که متد دقیقاً یک بار فراخوانی شده است. اگر تعداد متفاوتی نیاز باشد — از times(n)، atLeast(n)، never() و دیگر اصلاح‌کننده‌های کلاس Mockito استفاده می‌شود.

java
// بررسی تعداد فراخوانی‌ها
verify(repository, times(3)).save(any());
verify(repository, never()).delete(any());
verify(repository, atLeastOnce()).findById(1);

// بررسی ترتیب فراخوانی‌ها
InOrder inOrder = inOrder(repository);
inOrder.verify(repository).save(any());
inOrder.verify(repository).flush();

ArgumentCaptor برای ضبط آرگومان‌ها

زمانی که نیاز است بررسی شود متد با چه شیء دقیقی فراخوانی شده است، از ArgumentCaptor استفاده می‌شود. این ابزار مقدار آرگومان را هنگام فراخوانی ضبط می‌کند و امکان بررسی جداگانه فیلدهای آن را فراهم می‌کند. ArgumentCaptor به ویژه زمانی مفید است که کد تحت تست یک شیء را در داخل خود ایجاد کرده و به وابستگی منتقل می‌کند — این شیء را به روش دیگری نمی‌توان بررسی کرد.

java
ArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class);
verify(repository).save(captor.capture());
assertEquals("Alice", captor.getValue().getName());

@Mock و @InjectMocks

@Mock و @InjectMocks — دو annotation کلیدی Mockito هستند که کد تکراری را به طور قابل توجهی کاهش می‌دهند. @Mock برای فیلد یک mock ایجاد می‌کند و @InjectMocks تمام mockهای کلاس تست را از طریق سازنده، setter یا فیلد به شیء تحت تست تزریق می‌کند.

مکانیزم @InjectMocks سعی می‌کند وابستگی‌ها را به ترتیب زیر تزریق کند: سازنده با بیشترین تعداد آرگومان، setter بر اساس نوع، فیلد خصوصی. اگر هیچ روشی کار نکند — شیء با وابستگی‌های null باقی می‌ماند و تست با NullPointerException شکست می‌خورد.

قوانین استفاده از @InjectMocks

درک این نکته مهم است: @InjectMocks انواع فیلدها را تحلیل نمی‌کند — هر mock سازگار با نوع را جایگزین می‌کند. اگر کلاس دو فیلد از یک نوع داشته باشد — Mockito ممکن است mock اشتباهی را تزریق کند. در چنین مواردی توصیه می‌شود از سازنده صریح با ارسال mockها استفاده شود.

Mockito در پروژه‌های Android

در توسعه Android، Mockito همراه با JUnit برای تست ViewModel، Repository و UseCase استفاده می‌شود. از آنجا که این کلاس‌ها روی JVM بدون زمینه Android اجرا می‌شوند، Mockito وابستگی‌های آنها — Room DAO، Retrofit API، SharedPreferences — را با stubهای قابل پیش‌بینی جایگزین می‌کند.

تنظیمات Gradle برای Mockito

برای افزودن Mockito به پروژه Android، کافی است وابستگی mockito-core یا mockito-inline را اضافه کنید (دومی از mocking کلاس‌های final و متدهای استاتیک پشتیبانی می‌کند). نسخه 5.12.0 (2024) شامل پشتیبانی از Java 21 و ادغام بهبودیافته با JUnit 5 است.

kotlin
// build.gradle.kts (ماژول)
dependencies {
    testImplementation("org.mockito:mockito-core:5.12.0")
    testImplementation("org.mockito:mockito-junit-jupiter:5.12.0")
}

Mockito و PowerMock: رویه منسوخ

قبلاً برای mocking متدهای استاتیک و سازنده‌ها نیاز به PowerMock بود — افزونه‌ای که از طریق دستکاری بایت‌کد کار می‌کرد. از Mockito 5.x با mockito-inline، این قابلیت به طور مستقیم تعبیه شده است: mockStatic(ClassName.class) امکان mocking متدهای استاتیک بدون کتابخانه‌های اضافی را فراهم می‌کند.

تست ViewModel با Mockito

سناریوی معمول: ViewModel متد مخزن را فراخوانی می‌کند و نتیجه را به حالت UI تبدیل می‌کند. Mockito مخزن را جایگزین می‌کند و تست بررسی می‌کند که ViewModel پاسخ موفقیت و خطا را به درستی پردازش می‌کند. در معماری Clean Architecture، mockها برای هر لایه ایجاد می‌شوند: DataSource، Repository و UseCase — این امکان تست هر لایه را به صورت جداگانه فراهم می‌کند.

  • success case — when(repo.getData()).thenReturn(Result.success(data)) → state = Success(data) را بررسی می‌کنیم.
  • error case — when(repo.getData()).thenReturn(Result.error(exception)) → state = Error(message) را بررسی می‌کنیم.
  • loading state — verify که ViewModel قبل از فراخوانی مخزن isLoading = true تنظیم کرده است.

سوالات متداول

تفاوت Mockito با MockK چیست؟

Mockito کتابخانه‌ای برای Java و Kotlin است که از proxy و reflection استفاده می‌کند. MockK کتابخانه Kotlin-first با پشتیبانی از coroutine، extension functionها و کلاس‌های final بدون پیکربندی اضافی است.

چگونه برای کلاس final در Mockito mock ایجاد کنیم؟

از Mockito 2.1، mocking کلاس‌های final از طریق opt-in پشتیبانی می‌شود. در نسخه 5.x (mockito-inline) این قابلیت به طور پیش‌فرض فعال است. کافی است وابستگی mockito-inline را اضافه کنید و از متد استاندارد mock() استفاده کنید.

Spy در Mockito چیست؟

Spy یک mock جزئی است که به طور پیش‌فرض متدهای واقعی را فراخوانی می‌کند اما امکان بازنویسی برخی از آنها را از طریق when().thenReturn() می‌دهد. Spy برای تست کدهای legacy که نمی‌توان کل کلاس را بازنویسی کرد مفید است.

تفاوت thenReturn و thenAnswer چیست؟

thenReturn صرف‌نظر از آرگومان‌ها همیشه یک مقدار را برمی‌گرداند. thenAnswer مقدار بازگشتی را بر اساس فراخوانی — آرگومان‌ها، خود mock، وضعیت — محاسبه می‌کند. برای پاسخ‌های پویا همیشه از thenAnswer استفاده کنید.

چرا verify در تست‌های با mock مهم است؟

Verify نه تنها نتیجه، بلکه فرآیند — واقعیت مراجعه به وابستگی را بررسی می‌کند. این برای سرویس‌هایی که باید داده‌ها را ذخیره کنند یا اعلان ارسال کنند حیاتی است. بدون verify، تست تشخیص نمی‌دهد که متد save() یا send() را فراخوانی نکرده است.

خلاصه

  • Mockito — کتابخانه ایجاد اشیاء mock، استاندارد de facto برای mocking در Java و Kotlin.
  • Mockها از طریق mock(Class) یا annotation @Mock با MockitoExtension ایجاد می‌شوند.
  • Stubbing از طریق when().thenReturn() رفتار متدهای mock را تعیین می‌کند.
  • Verify واقعیت و تعداد فراخوانی‌های متدهای mock با آرگومان‌های مشخص را بررسی می‌کند.
  • @InjectMocks به طور خودکار mockها را به شیء تحت تست تزریق می‌کند.
  • ادغام با Android — Mockito برای تست ViewModel، Repository و UseCase استفاده می‌شود.
  • ArgumentCaptor آرگومان‌های فراخوانی را برای بررسی جزئیات فیلدهای شیء ضبط می‌کند.

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید