Mockito ایک اوپن سورس فریم ورک ہے جو Java اور Kotlin یونٹ ٹیسٹوں میں mock آبجیکٹ بنانے کے لیے ہے، جو ٹیسٹ کیے جانے والے کوڈ کو بیرونی انحصار سے الگ کرنے کی اجازت دیتا ہے۔ اس کی مدد سے، ڈیولپر حقیقی ریپوزٹریز، API کلائنٹس اور ڈیٹابیسز کو متعین رویے کے ساتھ کنٹرول شدہ stubs سے بدل دیتا ہے۔ Mockito.org کے مطابق، لائبریری یونٹ ٹیسٹنگ استعمال کرنے والے Java پروجیکٹس کے 60% سے زیادہ میں استعمال ہوتی ہے۔
اہم نکات
Mockito Java، Kotlin اور دیگر JVM زبانوں میں یونٹ ٹیسٹوں کے لیے mock آبجیکٹ (stubs) بنانے والی ایک اوپن سورس لائبریری ہے۔ JUnit کے برعکس، جو ٹیسٹ پر عملدرآمد کے لیے ذمہ دار ہے، Mockito علیحدگی کے مسئلے کو حل کرتا ہے — یہ ٹیسٹ کیے جانے والے کلاس کے حقیقی انحصار کو پیش قیاسی آبجیکٹس سے بدل دیتا ہے۔
mock کے بغیر، کسی ایسے میتھڈ کو ٹیسٹ کرنا جو ڈیٹابیس یا بیرونی API تک رسائی حاصل کرتا ہے، حقیقی ماحول قائم کرنے کی ضرورت ہوتی ہے — ڈیٹابیس تعینات کرنا، سرور شروع کرنا۔ Mockito ان انحصاروں کو مقررہ رویے والے آبجیکٹس سے بدل دیتا ہے: repository.findById(1) میتھڈ ڈیٹابیس تک رسائی کیے بغیر ہمیشہ ایک مخصوص User آبجیکٹ واپس کرتا ہے۔
Mockito کا فن تعمیر Proxy پیٹرن (انٹرفیسز اور کلاسز کے لیے) پر مبنی ہے۔ لائبریری مخصوص قسم کے لیے ایک ذیلی کلاس یا پراکسی تیار کرتی ہے اور تمام میتھڈ کالز کو روکتی ہے، ڈیفالٹ ویلیوز یا when().thenReturn() کے ذریعے سیٹ کردہ ویلیوز واپس کرتی ہے۔
Mockito کے کام کرنے کا اصول تین بنیادی کارروائیوں پر مبنی ہے: mock بنانا، رویے کو ترتیب دینا (stubbing) اور کالز کی تصدیق کرنا (verification)۔ ہر کارروائی Maven Central کے اعدادوشمار کے مطابق Java ایکو سسٹم میں سب سے زیادہ ڈاؤن لوڈ کردہ کلاس org.mockito.Mockito سے جامد میتھڈز استعمال کرتی ہے۔ تمام mock میتھڈ کالز میموری میں ریکارڈ کی جاتی ہیں، جو بعد میں verify کے ذریعے تصدیق کی اجازت دیتی ہیں۔
Mockito کے ساتھ ایک عام ٹیسٹ تین مراحل پر مشتمل ہوتا ہے: Arrange — when().thenReturn() کے ذریعے mocks بنانا اور stubs ترتیب دینا، Act — ٹیسٹ کیے جانے والے میتھڈ کو کال کرنا، Assert — assertEquals اور verify(mock) کے ذریعے نتیجہ جانچنا۔ اس طریقہ کار کو AAA (Arrange-Act-Assert) کہا جاتا ہے۔
ایک سادہ ٹیسٹ دیکھیں جہاں Mockito صارف ریپوزٹری کو بدل دیتا ہے۔ when().thenReturn() میتھڈ mock کو اس طرح ترتیب دیتا ہے کہ findById کال پہلے سے تیار کردہ User آبجیکٹ واپس کرے۔
// ریپوزٹری 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);
Mockito mocks بنانے کے دو طریقے فراہم کرتا ہے: جامد میتھڈ mock(Class) اور MockitoAnnotations.openMocks() کے ذریعے ابتدا کے ساتھ @Mock اینوٹیشن۔ پہلا طریقہ ایک یا دو mocks کے لیے کمپیکٹ ہے، دوسرا اس وقت آسان ہے جب بہت سے انحصار ہوں — اینوٹیشنز boilerplate کوڈ کو کم کرتی ہیں۔
mock() میتھڈ ایک کلاس لیتا ہے اور ایک stub آبجیکٹ واپس کرتا ہے جسے when().thenReturn() کے ذریعے ترتیب دیا جا سکتا ہے۔ تمام غیر ترتیب شدہ میتھڈز ڈیفالٹ ویلیوز واپس کرتے ہیں: نمبروں کے لیے 0، boolean کے لیے false، آبجیکٹس کے لیے null۔
ApiClient apiClient = mock(ApiClient.class);
Database database = mock(Database.class);
@Mock اینوٹیشن @ExtendWith(MockitoExtension.class) کے ساتھ مل کر ٹیسٹ کلاس کے تمام فیلڈز کے لیے خود بخود mocks بناتا ہے۔ MockitoExtension ہر ٹیسٹ سے پہلے ابتدا کے لیے ذمہ دار ہے۔
@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 میتھڈ کو کیا واپس کرنا چاہیے۔ بنیادی نحو: when(mock.method(args)).thenReturn(value)۔ مختلف منظرناموں کے لیے، Mockito کئی then-میتھڈ variants پیش کرتا ہے۔
| میتھڈ | مقصد |
|---|---|
| thenReturn(value) | ہمیشہ مخصوص قیمت واپس کرتا ہے |
| thenThrow(exception) | کال کرنے پر استثناء پھینکتا ہے |
| thenAnswer(answer) | واپسی کی قیمت کو متحرک طور پر شمار کرتا ہے |
| thenCallRealMethod() | حقیقی میتھڈ کو کال کرتا ہے (جزوی mock) |
جب واپسی کی قیمت کال آرگیومینٹس پر منحصر ہوتی ہے، تو lambda کے ساتھ thenAnswer استعمال کیا جاتا ہے۔ یہ حقیقی ڈیٹا کے ساتھ کام کی نقل کرنے کے لیے مفید ہے — مثال کے طور پر، موصولہ آبجیکٹ کی بنیاد پر ID تیار کرنا۔
when(repository.save(any())).thenAnswer(invocation -> {
User user = invocation.getArgument(0);
user.setId(42);
return user;
});
Verify Mockito کی ایک منفرد خصوصیت ہے جو پرانی mock آبجیکٹ لائبریریاں (EasyMock، jMock) فراہم نہیں کرتی ہیں۔
Verify ٹیسٹوں کو زیادہ قابل اعتماد بناتا ہے کیونکہ یہ نہ صرف واپسی کی قیمت بلکہ ضمنی اثرات — ان میتھڈز کی کالز جو نتیجہ واپس نہیں کرتی ہیں (void میتھڈز) — بھی جانچتا ہے۔ verify(mock).methodName(args) میتھڈ جانچتا ہے کہ آیا ایک مخصوص mock میتھڈ کو مخصوص آرگیومینٹس کے ساتھ کال کیا گیا تھا۔ یہ نہ صرف نتیجہ بلکہ عمل — انحصار تک رسائی کی حقیقت — کو بھی جانچنے کی اجازت دیتا ہے۔
ڈیفالٹ طور پر، verify جانچتا ہے کہ میتھڈ کو بالکل ایک بار کال کیا گیا تھا۔ اگر مختلف تعداد کی ضرورت ہو تو Mockito کلاس سے times(n)، atLeast(n)، never() اور دیگر موڈیفائر استعمال کیے جاتے ہیں۔
// کالوں کی تعداد کی جانچ
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<User> captor = ArgumentCaptor.forClass(User.class);
verify(repository).save(captor.capture());
assertEquals("Alice", captor.getValue().getName());
@Mock اور @InjectMocks دو اہم Mockito اینوٹیشنز ہیں جو boilerplate کوڈ کو نمایاں طور پر کم کرتی ہیں۔ @Mock ایک فیلڈ کے لیے mock بناتا ہے، اور @InjectMocks ٹیسٹ کلاس سے تمام mocks کو کنسٹرکٹر، سیٹر یا فیلڈ کے ذریعے ٹیسٹ کیے جانے والے آبجیکٹ میں انجیکٹ کرتا ہے۔
@InjectMocks میکانزم درج ذیل ترتیب میں انحصار انجیکٹ کرنے کی کوشش کرتا ہے: سب سے زیادہ آرگیومینٹس والا کنسٹرکٹر، قسم کے مطابق سیٹر، پرائیویٹ فیلڈ۔ اگر ان میں سے کوئی بھی طریقہ کام نہیں کرتا ہے، تو آبجیکٹ null انحصار کے ساتھ رہتا ہے، اور ٹیسٹ NullPointerException کے ساتھ ناکام ہو جائے گا۔
یہ سمجھنا ضروری ہے: @InjectMocks فیلڈ کی قسموں کا تجزیہ نہیں کرتا — یہ قسم کے مطابق کسی بھی ہم آہنگ mock کو بدل دیتا ہے۔ اگر ایک کلاس میں ایک ہی قسم کے دو فیلڈز ہیں، تو Mockito غلط mock انجیکٹ کر سکتا ہے۔ ایسی صورتوں میں، mock پیرامیٹرز کے ساتھ واضح کنسٹرکٹر استعمال کرنے کی سفارش کی جاتی ہے۔
Android ڈیولپمنٹ میں، Mockito JUnit کے ساتھ ViewModel، Repository اور UseCase کی جانچ کے لیے استعمال ہوتا ہے۔ چونکہ یہ کلاسز Android سیاق و سباق کے بغیر JVM پر چلتی ہیں، Mockito ان کے انحصار — Room DAO، Retrofit API، SharedPreferences — کو پیش قیاسی رویے والے stubs سے بدل دیتا ہے۔
Android پروجیکٹ میں Mockito شامل کرنے کے لیے، صرف mockito-core یا mockito-inline انحصار شامل کریں (مؤخر الذکر فائنل کلاسز اور جامد میتھڈز کے mocking کو سپورٹ کرتا ہے)۔ ورژن 5.12.0 (2024) Java 21 سپورٹ اور بہتر JUnit 5 انضمام شامل کرتا ہے۔
// build.gradle.kts (module)
dependencies {
testImplementation("org.mockito:mockito-core:5.12.0")
testImplementation("org.mockito:mockito-junit-jupiter:5.12.0")
}
پہلے، جامد میتھڈز اور کنسٹرکٹرز کے mocking کے لیے PowerMock — ایک توسیع جو بائٹ کوڈ انسٹرومینٹیشن کے ذریعے کام کرتی تھی — کی ضرورت تھی۔ Mockito 5.x سے mockito-inline کے ساتھ، یہ صلاحیت براہ راست شامل ہے: mockStatic(ClassName.class) اضافی لائبریریوں کے بغیر جامد میتھڈز کے mocking کی اجازت دیتا ہے۔
ایک عام منظرنامہ: ایک ViewModel ریپوزٹری میتھڈ کو کال کرتا ہے اور نتیجہ کو UI حالت میں تبدیل کرتا ہے۔ Mockito ریپوزٹری کو بدل دیتا ہے، اور ٹیسٹ جانچتا ہے کہ ViewModel کامیاب جواب اور غلطی دونوں کو درست طریقے سے ہینڈل کرتا ہے۔ Clean Architecture استعمال کرتے وقت، ہر پرت کے لیے mocks بنائے جاتے ہیں: DataSource، Repository اور UseCase — یہ ہر پرت کو الگ تھلگ جانچنے کی اجازت دیتا ہے۔
اکثر پوچھے گئے سوالات
Mockito Java اور Kotlin کے لیے ایک لائبریری ہے جو پراکسی اور عکاسی استعمال کرتی ہے۔ MockK ایک Kotlin-first لائبریری ہے جو اضافی ترتیب کے بغیر coroutines، توسیعی فنکشنز اور فائنل کلاسز کو سپورٹ کرتی ہے۔
Mockito 2.1 سے شروع کرتے ہوئے، فائنل کلاسز کا mocking opt-in کے ذریعے سپورٹ کیا جاتا ہے۔ ورژن 5.x (mockito-inline) میں، یہ ڈیفالٹ طور پر فعال ہے۔ بس mockito-inline انحصار شامل کریں اور معیاری mock() میتھڈ استعمال کریں۔
Spy ایک جزوی mock ہے جو ڈیفالٹ طور پر حقیقی میتھڈز کو کال کرتا ہے لیکن when().thenReturn() کے ذریعے ان میں سے کچھ کو اوور رائڈ کرنے کی اجازت دیتا ہے۔ Spy میراثی کوڈ کی جانچ کے لیے مفید ہے جب پوری کلاس کو دوبارہ نہیں لکھا جا سکتا۔
thenReturn ہمیشہ آرگیومینٹس سے قطع نظر ایک ہی قیمت واپس کرتا ہے۔ thenAnswer کال — کال آرگیومینٹس، خود mock اور حالت — کی بنیاد پر واپسی کی قیمت کا حساب لگاتا ہے۔ متحرک جوابات کے لیے، ہمیشہ thenAnswer استعمال کریں۔
Verify نہ صرف نتیجہ بلکہ عمل — انحصار تک رسائی کی حقیقت — بھی جانچتا ہے۔ یہ ان خدمات کے لیے اہم ہے جنہیں ڈیٹا محفوظ کرنا یا اطلاعات بھیجنی ہوتی ہیں۔ verify کے بغیر، ٹیسٹ یہ پتہ نہیں لگا سکے گا کہ کسی میتھڈ نے save() یا send() کو کال نہیں کیا۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں