Mockito — Java va Kotlin modul testlarida mock-obyektlar yaratish uchun ochiq kodli freymvork bo'lib, test qilinayotgan kodni tashqi bog'liqliklardan ajratish imkonini beradi. Uning yordamida dasturchi real repozitoriylarni, API mijozlarini va ma'lumotlar bazalarini boshqariladigan soxta obyektlar bilan almashtiradi. Mockito.org ma'lumotlariga ko'ra, kutubxona modul testlarini qo'llaydigan Java loyihalarining 60% dan ko'prog'ida ishlatiladi.
Asosiy ma'lumotlar
Mockito — Java, Kotlin va boshqa JVM tillarida modul testlarida mock-obyektlar (soxta obyektlar) yaratish uchun ochiq kodli kutubxona. JUnit testlarni ishga tushirish uchun javobgar bo'lsa, Mockito ajratish muammosini hal qiladi — test qilinayotgan sinfning real bog'liqliklarini oldindan bashorat qilinadigan obyektlar bilan almashtiradi.
Moklarsiz, ma'lumotlar bazasiga yoki tashqi API ga murojaat qiladigan metodni test qilish real muhitni sozlashni talab qiladi — DB ni o'rnatish, serverni ishga tushirish. Mockito bu bog'liqliklarni barqaror xatti-harakatga ega obyektlar bilan almashtiradi: repository.findById(1) metodi ma'lumotlar bazasiga murojaat qilmasdan har doim ma'lum User obyektini qaytaradi.
Mockito arxitekturasi Proxy naqshiga asoslanadi (interfeyslar va sinflar uchun). Kutubxona belgilangan tur uchun osti sinf yoki proksi yaratadi va barcha metod chaqiruvlarini ushlab, standart qiymatlarni yoki when().thenReturn() orqali belgilangan qiymatlarni qaytaradi.
Ishlash prinsipi Mockito uchta asosiy operatsiyaga asoslanadi: mock yaratish, xatti-harakatni sozlash (stubbing) va chaqiruvlarni tekshirish (verification). Har bir operatsiya Maven Central statistikasiga ko'ra Java ekotizimidagi eng ko'p yuklanadigan sinf bo'lgan org.mockito.Mockito sinfidan statik metodlardan foydalanadi. Mockning barcha metod chaqiruvlari xotiraga yoziladi, bu esa ularni verify orqali tekshirish imkonini beradi.
Mockito bilan odatdagi test uch bosqichdan iborat: Arrange — moklarni yaratish va stublarni when().thenReturn() bilan sozlash, Act — test qilinayotgan metodni chaqirish, Assert — natijani assertEquals va verify(mock) bilan tekshirish. Bu yondashuv AAA (Arrange-Act-Assert) deb ataladi.
Mockito foydalanuvchi repozitoriysini almashtiradigan sodda testni ko'rib chiqaylik. when().thenReturn() metodi mockni findById chaqiruvi oldindan tayyorlangan User obyektini qaytaradigan qilib sozlaydi.
// Repozitoriy mokini yaratamiz
UserRepository mockRepo = mock(UserRepository.class);
// Xatti-harakatni sozlaymiz: findById(1) da foydalanuvchini qaytar
when(mockRepo.findById(1)).thenReturn(new User("Alice"));
// Metodning haqiqatan chaqirilganligini tekshiramiz
User result = mockRepo.findById(1);
assertEquals("Alice", result.getName());
verify(mockRepo).findById(1);
Mockito mock yaratishning ikki usulini taqdim etadi: statik mock(Class) metodi va MockitoAnnotations.openMocks() orqali ishga tushiriladigan @Mock annotatsiyasi. Birinchi usul bir-ikkita mock uchun ixcham, ikkinchisi esa bog'liqliklar ko'p bo'lganda qulay — annotatsiyalar boilerplate kodni kamaytiradi.
mock() metodi sinfni qabul qiladi va when().thenReturn() orqali sozlanishi mumkin bo'lgan soxta obyektni qaytaradi. Sozlanmagan metodlar standart qiymatlarni qaytaradi: sonlar uchun 0, boolean uchun false, obyektlar uchun null.
ApiClient apiClient = mock(ApiClient.class);
Database database = mock(Database.class);
@Mock annotatsiyasi @ExtendWith(MockitoExtension.class) bilan birgalikda test sinfining barcha maydonlari uchun avtomatik moklar yaratadi. MockitoExtension kengaytmasi har bir testdan oldin ishga tushirish uchun javobgardir.
@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 — ma'lum argumentlar bilan chaqirilganda mock metodi nimani qaytarishi kerakligini aniqlash jarayoni. Asosiy sintaksis: when(mock.method(args)).thenReturn(value). Turli stsenariylar uchun Mockito bir nechta then-metod variantlarini taklif qiladi.
| Metod | Maqsad |
|---|---|
| thenReturn(value) | Har doim belgilangan qiymatni qaytaradi |
| thenThrow(exception) | Chaqiruvda istisno tashlaydi |
| thenAnswer(answer) | Qaytariladigan qiymatni dinamik hisoblaydi |
| thenCallRealMethod() | Haqiqiy metodni chaqiradi (qisman mock) |
Qaytariladigan qiymat chaqiruv argumentlariga bog'liq bo'lganda, lambda bilan thenAnswer ishlatiladi. Bu haqiqiy ma'lumotlar bilan ishlashni taqlid qilish uchun foydali — masalan, uzatilgan obyekt asosida ID generatsiyasi.
when(repository.save(any())).thenAnswer(invocation -> {
User user = invocation.getArgument(0);
user.setId(42);
return user;
});
Verify — Mockito-ning noyob imkoniyati bo'lib, eski mock-obyekt kutubxonalari (EasyMock, jMock) buni ta'minlamaydi.
Verify testlarni ishonchliroq qiladi, chunki u faqat qaytarilgan qiymatni emas, balki yon ta'sirlarni — natija qaytarmaydigan metod chaqiruvlarini (void metodlari) ham tekshiradi. verify(mock).methodName(args) metodi ma'lum mock metodining belgilangan argumentlar bilan chaqirilgan yoki chaqirilmaganligini tekshiradi. Bu nafaqat natijani, balki jarayonni — bog'liqlikka murojaat faktini ham test qilish imkonini beradi.
Standart bo'yicha verify metodning aniq bir marta chaqirilganligini tekshiradi. Agar boshqa son kerak bo'lsa — times(n), atLeast(n), never() va Mockito sinfidagi boshqa modifikatorlardan foydalaniladi.
// Chaqiruvlar sonini tekshirish
verify(repository, times(3)).save(any());
verify(repository, never()).delete(any());
verify(repository, atLeastOnce()).findById(1);
// Chaqiruvlar tartibini tekshirish
InOrder inOrder = inOrder(repository);
inOrder.verify(repository).save(any());
inOrder.verify(repository).flush();
Metod qaysi obyekt bilan chaqirilganligini tekshirish kerak bo'lganda, ArgumentCaptor ishlatiladi. U chaqiruv vaqtida argument qiymatini ushlab oladi va uning maydonlarini alohida tekshirish imkonini beradi. ArgumentCaptor ayniqsa test qilinayotgan kod ichki obyekt yaratib, uni bog'liqlikka uzatganda foydalidir — bu obyektni boshqa yo'l bilan tekshirib bo'lmaydi.
ArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class);
verify(repository).save(captor.capture());
assertEquals("Alice", captor.getValue().getName());
@Mock va @InjectMocks — Mockito-ning ikkita asosiy annotatsiyasi bo'lib, ular boilerplate kodni sezilarli darajada kamaytiradi. @Mock maydon uchun mock yaratadi, @InjectMocks esa test sinfidagi barcha moklarni test qilinayotgan obyektga konstruktor, setter yoki maydon orqali joylashtiradi.
@InjectMocks mexanizmi bog'liqliklarni quyidagi tartibda joylashtirishga harakat qiladi: eng ko'p argumentga ega konstruktor, tur bo'yicha setter, xususiy maydon. Agar hech qanday usul ishlamasa — obyekt null bog'liqliklari bilan qoladi va test NullPointerException bilan ishlamay qoladi.
Tushunish muhim: @InjectMocks maydon turlarini tahlil qilmaydi — turga mos keladigan har qanday mockni joylashtiradi. Agar sinfda bir xil turdagi ikkita maydon bo'lsa — Mockito noto'g'ri mockni joylashtirishi mumkin. Bunday hollarda moklarni uzatish bilan aniq konstruktordan foydalanish tavsiya etiladi.
Android rivojlanishida Mockito JUnit bilan birgalikda ViewModel, Repository va UseCase ni test qilish uchun ishlatiladi. Bu sinflar Android kontekstisiz JVM da ishlagani uchun Mockito ularning bog'liqliklarini — Room DAO, Retrofit API, SharedPreferences — oldindan bashorat qilinadigan stubalar bilan almashtiradi.
Mockito-ni Android loyihasiga qo'shish uchun mockito-core yoki mockito-inline bog'liqligini qo'shish kifoya (ikkinchisi final sinflar va statik metodlarni mock qilishni qo'llab-quvvatlaydi). 5.12.0 versiyasi (2024) Java 21 qo'llab-quvvatlash va JUnit 5 bilan yaxshilangan integratsiyani o'z ichiga oladi.
// build.gradle.kts (modul)
dependencies {
testImplementation("org.mockito:mockito-core:5.12.0")
testImplementation("org.mockito:mockito-junit-jupiter:5.12.0")
}
Ilgari statik metodlar va konstruktorlarni mock qilish uchun baytkod instrumentatsiyasi orqali ishlaydigan PowerMock kengaytmasi talab qilingan. Mockito 5.x dan mockito-inline bilan bu funksiya to'g'ridan-to'g'ri o'rnatilgan: mockStatic(ClassName.class) qo'shimcha kutubxonalarsiz statik metodlarni mock qilish imkonini beradi.
Odatdagi stsenariy: ViewModel repozitoriy metodini chaqiradi va natijani UI holatiga aylantiradi. Mockito repozitoriyni almashtiradi va test ViewModel ning muvaffaqiyatli javob va xatoni to'g'ri qayta ishlashini tekshiradi. Clean Architecture dan foydalanilganda, har bir qatlam uchun moklar yaratiladi: DataSource, Repository va UseCase — bu har bir qatlamni alohida test qilish imkonini beradi.
Tez-tez beriladigan savollar
Mockito — proksi va refleksiyadan foydalanadigan Java va Kotlin uchun kutubxona. MockK — koroutine, extension funksiyalar va final sinflarni qo'shimcha konfiguratsiyasiz qo'llab-quvvatlaydigan Kotlin-first kutubxona.
Mockito 2.1 dan boshlab final sinflarni mock qilish opt-in orqali qo'llab-quvvatlanadi. 5.x versiyasida (mockito-inline) bu standart sifatida yoqilgan. Faqat mockito-inline bog'liqligini qo'shish va standart mock() metodidan foydalanish kifoya.
Spy — standart bo'yicha haqiqiy metodlarni chaqiradigan, lekin ba'zilarini when().thenReturn() orqali qayta belgilashga imkon beradigan qisman mock. Spy butun sinfni qayta yozish mumkin bo'lmagan legacy kodni test qilish uchun foydali.
thenReturn argumentlardan qat'iy nazar har doim bir xil qiymatni qaytaradi. thenAnswer qaytariladigan qiymatni chaqiruv asosida hisoblaydi — argumentlar, mocking o'zi, holat. Dinamik javoblar uchun har doim thenAnswer dan foydalaning.
Verify nafaqat natijani, balki jarayonni — bog'liqlikka murojaat faktini tekshiradi. Bu ma'lumotlarni saqlashi yoki bildirishnomalar yuborishi kerak bo'lgan xizmatlar uchun juda muhim. Verify bo'lmasa, test metod save() yoki send() chaqirmaganligini aniqlay olmaydi.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.