MockK — bu Kotlin-first freymvork bo'lib, mock-obyektlar yaratish uchun mo'ljallangan va Kotlin ekotizimi uchun uning til xususiyatlarini hisobga olgan holda ishlab chiqilgan: korutinlar, extension-funksiyalar, data class va sealed class. Java-dan Kotlin-ga port qilingan Mockito-dan farqli o'laroq, MockK boshidanoq Kotlin sintaksisi uchun yaratilgan va final-klasslar bilan ishlash uchun qo'shimcha plaginlarni talab qilmaydi. MockK.io ma'lumotlariga ko'ra, kutubxona modul testlari bilan Kotlin loyihalarining 40% dan ko'prog'ida qo'llaniladi.
Asosiy ma'lumotlar
MockK — bu Kotlin tilida yozilgan va uning sintaksisi uchun optimallashtirilgan mock-obyektlarni yaratish kutubxonasi. U Mockito bilan bir xil vazifalarni hal qiladi — test qilinayotgan kodni bog'liqliklardan izolyatsiya qilish — lekin buni Kotlin-ga xos konstruksiyalar yordamida amalga oshiradi: lambdalar, DSL, reified generics va suspend-funksiyalar.
MockK-ning port qilingan yechimlarga nisbatan asosiy afzalligi — Kotlin-ning native qo'llab-quvvatlanishi. Mockito-da final-klasslarni mock qilish opt-in talab qiladi (mockito-inline), statik usullar esa — mockStatic. MockK buni standart sifatida qo'llab-quvvatlaydi, chunki Kotlin klasslari standart sifatida final hisoblanadi va bu cheklovni chetlab o'tish kutubxona arxitekturasiga o'rnatilgan.
1.13.12 versiyasi (2024) — Kotlin 2.0, K2 kompilyator va ko'p platformali loyihalarni (KMP) qo'llab-quvvatlaydigan barqaror reliz. MockK shuningdek Kotlin/Native va Kotlin/JS bilan ishlaydi, bu esa uni Mockito ham, EasyMock ham qo'llanilmaydigan KMP loyihalari uchun yagona tanlovga aylantiradi.
MockK Kotlin-ning o'ziga xosligini hisobga olgan holda ishlab chiqilgan va til imkoniyatlaridan — reified generics, lambdalar bilan DSL, inline funksiyalar — unumdorlikni yo'qotmasdan ixcham va tip-xavfsiz API ta'minlash uchun foydalanadi.
Mexanizm MockK ByteBuddy kutubxonasi orqali baytkod-instrumentatsiyasiga asoslanadi (Mockito kabi), lekin uni Kotlin-ga mos DSL-ga o'raydi. when().thenReturn() zanjirlari o'rniga MockK every { } va coEvery { } lambda bloklaridan foydalanadi, ular tilning tabiiy kengaytmasi sifatida ko'rinadi. Ichkarida, MockK lambda ichidagi chaqiruvni tutadi, usul va argumentlarni refleksiya orqali tahlil qiladi va ularni yozilgan stubbing qoidalariga moslashtiradi.
every { mock.method() } returns value bloki "har safar usul chaqirilganda, qiymatni qaytar" deb o'qiladi. Bunday deklarativ sintaksis Kotlin uslubiga yaqinroq va when() dagi argumentlar tartibi bilan chalkashlikni bartaraf qiladi. Kotlin-ning reified generics tufayli, mock turi klassni aniq ko'rsatmasdan avtomatik ravishda chiqariladi.
val repository = mockk<UserRepository>()
// Stubbing: har bir findById(1) chaqiruvi foydalanuvchini qaytaradi
every { repository.findById(1) } returns User("Alice")
// Chaqiruv va tekshirish
val result = repository.findById(1)
assertEquals("Alice", result.name)
Har bir usulni aniq sozlash kerak bo'lgan Mockito-dan farqli o'laroq, MockK relaxed mock — har qanday usul uchun "oqilona" standart qiymatlarni qaytaradigan mock-ni qo'llab-quvvatlaydi: List uchun bo'sh ro'yxat, Int uchun 0, String uchun bo'sh qator. Bu tayyorgarlik kodining hajmini keskin kamaytiradi.
// Relaxed mock — barcha usullar standart qiymatlarni qaytaradi
val api = mockk<ApiService>(relaxed = true)
// Stubbing talab qilmaydi — bo'sh ro'yxatni qaytaradi
println(api.getUsers()) // []
MockK mock-obyektlarni yaratishning bir necha usullarini taklif qiladi: qattiq mock uchun mockk<T>() (har bir usul aniq sozlanishi kerak), relaksatsiyalangan mock uchun mockk<T>(relaxed = true) va haqiqiy obyektda josus yaratish uchun spyk(obj).
| Funksiya | Tur | Stubbingsiz xatti-harakat |
|---|---|---|
| mockk() | Qattiq mock | Stub qilinmagan usul chaqirilganda istisno tashlaydi |
| mockk(relaxed = true) | Relaksatsiyalangan mock | Standart qiymatni qaytaradi |
| spyk() | Josus | Stub sozlanmagan bo'lsa, haqiqiy usulni chaqiradi |
| slot() | Argument Captor | Tekshirish uchun argumentni ushlaydi |
Qattiq va relaksatsiyalangan mock o'rtasidagi tanlov kontekstga bog'liq. Qattiq mock testning xatti-harakati aniqlanmagan usullardan foydalanmasligini kafolatlaydi — bu ishonchlilikni oshiradi. Relaksatsiyalangan mock barcha bog'liqliklar muhim bo'lmagan tezkor test prototiplash uchun qulay. Amalda, qattiq mockdan boshlash va faqat stubbing testning o'zidan ko'proq satrni egallaganida relaxed-ga o'tish tavsiya etiladi.
Every bloki — MockK-da stubbingning markaziy konstruksiyasi. Lambda ichida aniq argumentlar bilan usul chaqiruvi tasvirlanadi, so'ngra returns orqali qiymat qaytariladi, throws orqali istisno tashlanadi yoki answers orqali javob hisoblanadi.
MockK test uchun zarur bo'lgan barcha stsenariylarni qo'llab-quvvatlaydi: qiymat qaytarish, istisno tashlash, argumentlar asosida javob hisoblash, ketma-ket bir nechta javoblar (chaqiruvlar ketma-ketligi).
// Qiymat qaytarish
every { repo.findById(1) } returns User("Alice")
// Istisno tashlash
every { repo.findById(999) } throws NotFoundException()
// Dinamik javob
every { repo.save(any()) } answers {
val user = firstArg<User>()
user.copy(id = 42)
}
// Javoblar ketma-ketligi
every { repo.findAll() } returnsMany listOf(
listOf(User("Alice")),
listOf(User("Bob")),
emptyList()
)
Verify MockK-da ma'nosi bo'yicha Mockito.verify()-ga o'xshaydi, lekin Kotlin DSL-dan foydalanadi: verify { mock.method() }. Suspend-funksiyalar uchun coVerify { mock.suspendMethod() } ishlatiladi, u korutinlar bilan to'g'ri ishlaydi va maxsus runner talab qilmaydi.
MockK Mockito bilan bir xil modifikatorlarni qo'llab-quvvatlaydi: exactly(1), atLeast(2), atMost(5), wasNot(Called). Sintaksis minimalist — modifikator verify { } da birinchi argument sifatida uzatiladi.
// Tekshirish: usul aniq 1 marta chaqirildi
verify(exactly = 1) { repo.save(any()) }
// Chaqiruvlar tartibini tekshirish
verifySequence {
repo.save(any())
repo.flush()
}
// Suspend funksiyalar uchun coVerify
coVerify { api.fetchUsers() }
Argumentlarni tekshirish uchun slot() — ArgumentCaptor analogi ishlatiladi. Slot chaqiruvdan oldin e'lon qilinadi, every yoki verify ga uzatiladi va test bajarilgandan so'ng ushlangan qiymatni o'z ichiga oladi.
val userSlot = slot<User>()
verify { repo.save(capture(userSlot)) }
assertEquals("Alice", userSlot.captured.name)
MockK JUnit 5 da initsializatsiya orqali mocklar yaratish uchun @MockK va @RelaxedMockK annotatsiyalarini taqdim etadi. MockKExtension kengaytmasi har bir testdan oldin avtomatik ravishda mocklar yaratadi va keyin tozalaydi — MockitoExtension-ga o'xshash, lekin relaxed rejimini qo'llab-quvvatlaydi.
@InjectMockKs annotatsiyasi (yoki obyektni aniq yaratish bilan @MockK muqobili) mocklarni test qilinayotgan nusxaga kiritadi. Bu boilerplate-ni kamaytiradi va test kodini toza qiladi.
@ExtendWith(MockKExtension::class)
class UserServiceTest {
@MockK
lateinit var repository: UserRepository
@InjectMockKs
lateinit var service: UserService
@Test
fun `getUser returns user from repository`() {
every { repository.findById(1) } returns User("Alice")
assertEquals("Alice", service.getUser(1)?.name)
}
}
Tanlov MockK va Mockito o'rtasida jamoa tarkibi va loyiha turiga bog'liq. Mockito kattaroq ekotizimga, ko'proq misollar va integratsiyalarga ega, ammo MockK tozaroq Kotlin sintaksisi va til xususiyatlarining native qo'llab-quvvatlanishini ta'minlaydi. Yangi Kotlin loyihalari uchun MockK ko'proq idiomatik yechim sifatida tavsiya etiladi.
| Mezon | MockK | Mockito |
|---|---|---|
| Sintaksis | Kotlin DSL (every, verify) | Java uslubi (when, thenReturn) |
| Korutinlar | coEvery, coVerify (native) | Qo'shimcha kutubxonalar talab qiladi |
| Final class | Standart sifatida qo'llab-quvvatlanadi | mockito-inline talab qiladi |
| KMP | Qo'llab-quvvatlanadi | Qo'llab-quvvatlanmaydi |
| Relaxed mock | Ichki | Analogi yo'q |
| Mashhurlik | Kotlin jamoasida o'sib bormoqda | Java va gibrid loyihalarda ustunlik qiladi |
Sof Kotlin loyihalari uchun (Java klasslarisiz) MockK afzal: kamroq boilerplate, korutinlarning native qo'llab-quvvatlanishi, final-klasslar bilan kutilmagan hodisalar yo'q. Gibrid loyihalar yoki Java tajribasiga ega jamoalar uchun Mockito ishlaydigan variant bo'lib qoladi — ikkala kutubxona ham bir loyihada turli modullar orqali ishlatilishi mumkin. Mockito-dan MockK-ga migratsiya qilishda @Mock annotatsiyalarini @MockK bilan almashtirish va when().thenReturn() bloklarini every { } formatiga o'zgartirish kifoya.
Tez-tez beriladigan savollar
Relaxed mock barcha stub qilinmagan usullar uchun standart qiymatlarni qaytaradi (bo'sh ro'yxat, 0, null), istisno tashlamasdan. Oddiy (strict) mock har bir usulning aniq stubbingini talab qiladi — aks holda test muvaffaqiyatsiz bo'ladi. Relaxed mock tezkor testlar uchun qulay, strict — ishonchli testlar uchun.
MockK extension-funksiyalarni mockkStatic() orqali mock qilishni qo'llab-quvvatlaydi. Bu mumkin, chunki Kotlin-dagi extension-funksiyalar birinchi parametr qabul qiluvchi statik usullardir. Har bir extension-funksiya uchun u e'lon qilingan klassni ko'rsatish kerak.
Ha, MockK umumiy kod uchun Kotlin Multiplatform (KMP) ni qo'llab-quvvatlaydi. JVM, Native va JS platformalarida umumiy API dan foydalanish mumkin: mockk(), every, verify. Bu MockK-ni Mockito ishlamaydigan KMP loyihalari uchun yagona tanlovga aylantiradi.
verifySequence { } dan foydalaning — chaqiruvlar kutilgan tartibda qat'iy ko'rsatilgan blok. Haqiqiy tartib farq qilsa, verifySequence birinchi mos kelmaydigan chaqiruvni ko'rsatib, istisno tashlaydi.
Ha, texnik jihatdan mumkin, ammo tavsiya etilmaydi. Mojarolar baytkod-instrumentatsiya darajasida yuzaga kelishi mumkin (ByteBuddy vs mockito-inline). Agar loyiha allaqachon Mockito-dan foydalanayotgan bo'lsa, MockK-ga migratsiya modullarni izolyatsiya qilish orqali bosqichma-bosqich amalga oshirilishi mumkin.
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.