Mock — bu nima, mock-obyektlar va testlar uchun kutubxonalar

Muallif: IT Sectr Nashr etilgan: 2026-04-10 O'qish vaqti: 8 daq

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 — o'zaro aloqani tekshiruvchi obyekt: qaysi metodlar chaqirildi, qanday argumentlar bilan va necha marta
  • Mockito — Java va Android loyihalarida Mock yaratish uchun eng mashhur kutubxona
  • MockK — Kotlin uchun Mockito-ga muqobil, koroutinlar va sealed class uchun mahalliy qo'llab-quvvatlash bilan
  • Behavior verification — Mock-ni Stub-dan asosiy farqi: Mock xatti-harakatni tekshiradi, holatni emas
  • Over-mocking — asosiy Anti-Pattern: mock faqat tashqi bog'liqliklar uchun bo'lishi kerak

Mock nima?

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 qanday ishlaydi

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 qachon zarur

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: batafsil taqqoslash

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.

MezonMockStub
Asosiy savolMetod chaqirildimi?Qanday natija qaytarildi?
TekshirishXatti-harakat (verify)Holat (assert)
Ma'lumot qaytarishIxtiyoriyMajburiy
Misolverify(analytics).logEvent("click")assertEquals(5, repository.getCount())
Qachon ishlatiladiYon ta'sirlarMa'lumot qaytarish

Amaliy qoida: Mock yoki yo'q

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: kutubxonalarni taqqoslash

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: isbotlangan klassika

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: Kotlin-first yondashuvi

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.

kotlin
// Mockito + mockito-kotlin
val repository = mock<UserRepository>()
whenever(repository.getUser(1)).thenReturn(user)

// MockK
val repository = mockk<UserRepository>()
every { repository.getUser(1) } returns user

Ishlash taqqoslashi

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.

Kotlin-da Mock testlari misollari

Uch stsenariyni ko'rib chiqamiz: Mock bog'liqliklari bilan ViewModel-ni testlash, API chaqiruvini tekshirish bilan UseCase-ni testlash va coVerify bilan koroutinlarni testlash.

Misol 1: Mock analitika bilan ViewModel

kotlin
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") }
    }
}

Misol 2: Asinxron tekshirish bilan UseCase

kotlin
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)
    }
}

Misol 3: ArgumentCaptor bilan argumentlarni tekshirish

kotlin
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])
    }
}

Mock testlashning eng yaxshi amaliyotlari

Mobil ishlanmada Mock-dan samarali foydalanish intizom talab qiladi. Ushbu qoidalarning buzilishi testlarni har bir refaktoringda sinadigan mo'rt to'siqlarga aylantiradi.

Faqat ilovaning tashqi chegaralarini mock qiling

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 testda bitta assert/verify

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.

  • MockK-da relaxUnitFun = true ishlating Unit qaytaruvchi metodlar uchun — aks holda Mock tasvirlanmagan chaqiruvda istisno tashlaydi
  • Verify-ni faqat muhim chaqiruvlar bilan cheklang — har bir getter va setterni tekshirmang, bu testlarni mo'rt qiladi
  • ArgumentMatchers-ni mazmunli ishlating — argument biznes mantig'i uchun muhim bo'lsa, any() muhim tafsilotlarni yashiradi
  • verifyNoMoreInteractions-dan suiiste'mol qilmang — bu metod testni ishlab chiqarish kodidagi har qanday o'zgarishga nisbatan keraksiz darajada qattiq qiladi
  • @MockkAnnotations dan foydalaning Mock-obyektlarni avtomatik ishga tushirish uchun — bu boilerplate-ni kamaytiradi va o'qishni yaxshilaydi

Mock testlashning ilg'or texnikalari

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.

SpyK bilan Partial Mock

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.

Turbine bilan StateFlow-ni testlash

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.

kotlin
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 Mockito-dan nimasi bilan farq qiladi?

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).

Mock Kotlin koroutinlari bilan qanday ishlaydi?

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.

Mock takroriy chaqiruvlarda turli qiymatlarni qaytara oladimi?

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.

Testlar orasida Mock holatini qanday tozalash mumkin?

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.

Mock Kotlin-da sealed class-ni qanday boshqaradi?

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

  • Mock — bog'liqliklarning holatini (assert) emas, balki xatti-harakatini (verify) tekshiruvchi Test Double turi
  • Mockito — Java/Android uchun standart, MockK — koroutin va sealed class qo'llab-quvvatlashi bilan Kotlin-first tanlov
  • Asosiy qoida: Mock tashqi chegaralar uchun (tarmoq, MB, tizim xizmatlari), real obyektlar ichki sinflar uchun
  • Over-mocking — asosiy Anti-Pattern: bog'liqliklarni haddan tashqari almashtirish testlarni mo'rt va kam foydali qiladi
  • Bitta test — bitta mantiqiy tekshirish: Mock uchun verify yoki Stub uchun assert, lekin bir testda ikkalasi emas
  • ArgumentCaptor / slot — ko'r any() o'rniga Mock chaqiruv argumentlarini tekshirishning to'g'ri usuli
  • MockK Kotlin loyihalari uchun tavsiya etiladi: coEvery va coVerify qo'shimcha adapterlarsiz koroutinlar bilan mahalliy ishlaydi

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.

Loyihani muhokama qilish

Shuningdek o'qing