Mock — real komponentning xatti-harakatini taqlid qiluvchi va u bilan o'zaro aloqani tekshirish imkonini beruvchi o'rinbosar obyektdir. Shunchaki berilgan qiymatni qaytaradigan Stub-dan farqli o'laroq, Mock metodning chaqirilish faktini, uzatilgan argumentlarni va chaqiruvlar sonini qayd etadi. Mockito (2024) ma'lumotlariga ko'ra, Mock Java va Kotlin loyihalarida eng mashhur Test Double turi bo'lib, mobil ilovalarning unit-testlarining 70% dan ortig'ida qo'llaniladi.
Asosiy ma'lumotlar
Mock — mocking freymvorki (Mockito, MockK, EasyMock) tomonidan yaratilgan, interfeys yoki sinfni taqlid qiluvchi va barcha metod chaqiruvlarini qayd etuvchi obyektdir. Dasturchi kutishlarni belgilaydi: X metodi Y argumentlari bilan chaqiriladi va Z qaytaradi. Test bajarilgandan so'ng, Mock kutishlarning haqiqiy chaqiruvlarga mos kelishini tekshiradi.
Termin Test Doubles-ning teatr metaforasidan kelib chiqqan: Mock — „taqlidchi“ bo'lib, u nafaqat sahnada turadi (Dummy kabi), balki rol o'ynaydi va u bilan o'zaro aloqa to'g'ri bo'lganligini tekshiradi. Agar sinovdan o'tkazilayotgan kod Mock kutgan metodni chaqirmagan bo'lsa yoki noto'g'ri argumentlar bilan chaqirgan bo'lsa — test buzilgan kutish haqidagi xabar bilan muvaffaqiyatsiz bo'ladi.
Mock freymvork fabrikasi orqali yaratiladi: mockk<MyInterface>() yoki Mockito.mock(MyClass.java). Freymvork barcha metod chaqiruvlarini tutib oluvchi proksi-obyektni yaratadi. Har bir chaqiruv oldindan belgilangan kutishlar (expectations) bilan taqqoslanadi. Agar chaqiruv kutishga mos kelsa — berilgan qiymat qaytariladi. Agar yo'q bo'lsa — Mock konfiguratsiyaga qarab standart qiymat qaytaradi yoki istisno tashlaydi.
Mock sinovdan o'tkazilayotgan kod yon ta'sirga ega komponentlar bilan o'zaro aloqada bo'lganda majburiydir: ma'lumotlarni serverga jo'natish, ma'lumotlar bazasiga yozish, loglash, analitika, navigatsiya, tizim dialoglarini ko'rsatish. Mock bo'lmasa, bu o'zaro aloqalarni real infratuzilmani ishga tushirmasdan tekshirish mumkin emas. Google Testing Blog-ga ko'ra, Mock ilova analitik hodisani haqiqatan ham yuborganligini test serverini ko'tarmasdan tekshirishning yagona usulidir.
Mock va Stub o'rtasidagi farq testlashda eng ko'p muhokama qilinadigan mavzulardan biridir. Ikkala tur ham real bog'liqlikni almashtiradi, ammo tubdan farqli usullar bilan.
| Mezon | Mock | Stub |
|---|---|---|
| Asosiy savol | Metod chaqirildimi? | Qanday natija qaytarildi? |
| Tekshirish | Xatti-harakat (verify) | Holat (assert) |
| Ma'lumot qaytarish | Ixtiyoriy | Majburiy |
| Misol | verify(analytics).logEvent("click") | assertEquals(5, repository.getCount()) |
| Qachon ishlatiladi | Yon ta'sirlar | Ma'lumot qaytarish |
Tanlash uchun oddiy test: o'zingizdan so'rang — „agar men ushbu kod qatorini o'chirsam, test muvaffaqiyatsiz bo'ladimi?“. Agar test qaytarilgan qiymatni tekshirsa — Stub kerak (assert orqali tekshirish). Agar test kodning metodni to'g'ri argumentlar bilan chaqirganligini tekshirsa — Mock kerak (verify orqali tekshirish). Bu dixotomiya Command-Query Separation namunasidan kelib chiqadi: holatni o'zgartiruvchi metodlar (commands) Mock talab qiladi; ma'lumot qaytaruvchi metodlar (queries) Stub talab qiladi.
Mockito va MockK o'rtasida tanlov Kotlin-da Android loyihasining test to'plamini sozlashdagi birinchi qarorlardan biridir. Ikkala kutubxona ham bir vazifani bajaradi, ammo Kotlin xususiyatlariga turlicha yondashadi.
Mockito — Java loyihalari uchun de-fakto standartdir. 5.x versiyasi o'rnatilgan MockMaker tufayli final sinflar, statik metodlar va konstruktorlar uchun mock-obyektlarni qo'llab-quvvatlaydi. Kotlin loyihalari uchun Mockito qo'shimcha sozlashni talab qiladi: yaxshilangan sintaksis uchun mockito-kotlin kengaytmalari, final sinflar uchun mockito-inline. Mockito qo'shimcha adapterlarsiz Kotlin koroutinlari va suspend funksiyalarini qo'llab-quvvatlamaydi.
MockK maxsus Kotlin uchun yaratilgan. U koroutinlarni (coEvery, coVerify), sealed class, data class, obekt-singletonlarni va extension funksiyalarni mahalliy qo'llab-quvvatlaydi. MockK sintaksisi lambda bloklari bilan DSL-dan foydalanadi, bu Kotlin kodida tabiiy ko'rinadi. MockK shuningdek qo'shimcha sozlashsiz xususiyatlarni (property mocking) mock qila oladi — bu LiveData, StateFlow va Delegates ishlatadigan Android loyihalari uchun muhimdir.
// Mockito + mockito-kotlin
val repository = mock<UserRepository>()
whenever(repository.getUser(1)).thenReturn(user)
// MockK
val repository = mockk<UserRepository>()
every { repository.getUser(1) } returns user
Benchmarklar (JVM Benchmark, 2024) MockK Kotlin loyihalari uchun mock-obyektlarni Mockito-dan 15–20% tezroq yaratishini ko'rsatadi, chunki Java Reflections emas, balki to'g'ridan-to'g'ri Kotlin bytecode bilan ishlaydi. Minglab unit-testlari bo'lgan loyihalarda qurilish vaqtidagi farq sezilarli bo'lishi mumkin: MockK katta loyihalarda testlarning to'liq bajarilishida 30–60 soniya tejaydi.
Uch stsenariyni ko'rib chiqamiz: Mock bog'liqliklari bilan ViewModel-ni testlash, API chaqiruvini tekshirish bilan UseCase-ni testlash va coVerify bilan koroutinlarni testlash.
class ProfileViewModelTest {
private val analytics = mockk<AnalyticsService>()
private val repo = mockk<UserRepository>()
private val vm = ProfileViewModel(repo, analytics)
fun `profile opened logs analytics event`() {
every { analytics.logEvent("profile_opened") } returns Unit
vm.onViewCreated()
verify { analytics.logEvent("profile_opened") }
}
}
class SendMessageUseCaseTest {
private val api = mockk<MessagingApi>()
private val useCase = SendMessageUseCase(api)
fun `send message with correct payload`() = runTest {
val message = Message(text = "Hello", userId = 42)
coEvery { api.sendMessage(any()) } returns MessageResult.Sent("msg_1")
val result = useCase.execute(message)
coVerify {
api.sendMessage(match {
it.text == "Hello" && it.userId == 42
})
}
assertTrue(result is MessageResult.Sent)
}
}
class OrderUseCaseTest {
private val api = mockk<OrderApi>()
private val useCase = OrderUseCase(api)
private val slot = slot<OrderRequest>()
fun `order request contains correct items`() = runTest {
coEvery { api.placeOrder(capture(slot)) } returns OrderResult.Placed("order_1")
useCase.execute(listOf("item_a", "item_b"))
assertEquals(2, slot.captured.items.size)
assertEquals("item_a", slot.captured.items[0])
}
}
Mobil ishlanmada Mock-dan samarali foydalanish intizom talab qiladi. Ushbu qoidalarning buzilishi testlarni har bir refaktoringda sinadigan mo'rt to'siqlarga aylantiradi.
Qattiq qoida: Mock faqat ilova chegarasini kesib o'tuvchi bog'liqliklar uchun yaratiladi: API mijozlari, ma'lumotlar bazalari, fayl tizimi, tizim xizmatlari (LocationManager, BluetoothAdapter, Camera). Ilovaning ichki sinflari — domen subyektlari, Value Object, oddiy yordamchi vositalar — Mock bilan almashtirilmasligi kerak. Ularning xatti-harakati real obyektlar orqali testlanadi.
Har bir test aniq bitta mantiqiy tekshirishni o'z ichiga olishi kerak — yo verify (Mock uchun), yoki assert (Stub uchun). Bir testda holat va xatti-harakat tekshiruvini aralashtirmang. Agar API chaqiruvini ham, natijani ham tekshirish kerak bo'lsa — turli nomlar bilan ikkita alohida test yarating. „Har bir testda bitta assert“ sifatida tanilgan bu qoida Kent Beck (2002) tavsiyalaridan kelib chiqqan.
Asosiy mocking-dan tashqari, mobil ishlanmada o'ziga xos muammolarni hal qiluvchi ilg'or texnikalar mavjud: ko'p tarmoqlilikni testlash, Flow holatini tekshirish va real obyektlarni qisman mock qilish.
Spy (yoki partial mock) chaqiruvlarni real amalga oshirishga yo'naltiruvchi, lekin alohida metodlarni bekor qilish imkonini beruvchi obyekt yaratishga imkon beradi. MockK-da spyk sinfning real instansiyasi asosida yaratiladi: val repo = spyk(InMemoryUserRepository()). every orqali kutishlar belgilangan chaqiruvlar Mock orqali o'tadi; qolganlari — real obyekt orqali. Spy, ayniqsa, bog'liqlik inyeksiyasi hali joriy qilinmagan legacy-kodni testlash uchun foydali, faqat bitta metodni bekor qilish kerak bo'lganda.
Jetpack Compose-dagi zamonaviy Android loyihalarida ViewModel holatni StateFlow orqali taqdim etadi. MockK Flow bog'liqliklarini mock qilish imkonini beradi, Turbine kutubxonasi esa emissiyani tekshirishni soddalashtiradi. Klassik namuna: Flow qaytaruvchi UseCase uchun MockK, ViewModel emissiyasini tekshirish uchun Turbine. Ushbu to'plam Kotlin Coroutines bo'yicha Android Testing (Google, 2024) hujjatlari tomonidan tavsiya etiladi.
class SearchViewModelTest {
private val searchUseCase = mockk<SearchUseCase>()
private val vm = SearchViewModel(searchUseCase)
fun `search emits results`() = runTest {
coEvery { searchUseCase.search("android") } returns
flowOf(SearchResult.Success(listOf(Item("Android TDD"))))
vm.search("android")
vm.state.test {
val state = awaitItem()
assertTrue(state.items.isNotEmpty())
cancelAndIgnoreRemainingEvents()
}
}
}
Tez-tez beriladigan savollar
Mock — bu tushuncha, xatti-harakatni tekshiruvchi Test Double turi. Mockito — Java va Android-da Mock-obyektlar yaratish uchun kutubxona. Boshqa kutubxonalar: MockK (Kotlin), EasyMock (Java), Cuckoo (iOS).
Suspend funksiyalarini Mock bilan testlash uchun MockK (coEvery / coVerify) yoki mockito-kotlin bilan Mockito dan foydalaning. MockK koroutinlarni mahalliy qo'llab-quvvatlaydi: coEvery suspend funksiyasining xatti-harakatini belgilaydi, coVerify uning koroutin ichida chaqirilishini tekshiradi. Barcha suspend chaqiruvlar runTest (kotlinx-coroutines-test) ichida bajarilishi kerak.
Ha. MockK-da buning uchun returnsMany ishlatiladi: every { api.getData() } returnsMany listOf(response1, response2). Mockito-da — thenReturn(value1).thenReturn(value2) zanjiri. Bu ketma-ket chaqiruvlarda turli javoblar bilan xatti-harakatni testlash uchun foydali.
MockK-da @MockK annotatsiyasini relaxed = true maydoni bilan ishlating va @After metodida clearMocks(mock) ni chaqiring. Mockito-da — Mockito.reset(mock). Eng yaxshi amaliyot: testlar orasidagi ta'sirni istisno qilish uchun har bir test uchun @Before orqali yangi Mock yarating.
MockK sealed class bilan to'g'ri ishlaydi: every { useCase() } returns Result.Success(data). Mockito sealed class-ni to'g'ridan-to'g'ri qo'llab-quvvatlamaydi, aylanma yo'llarni talab qiladi. Bu Kotlin loyihalari uchun Mockito o'rniga MockK tavsiya etilishining sabablaridan biridir.
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.