Mock — ano ito, mga mock-object at mga library para sa pagsubok

May-akda: IT Sectr Nai-publish: 2026-04-10 Oras ng pagbabasa: 8 min

Mock — ay isang kapalit na bagay na ginagaya ang pag-uugali ng isang tunay na component at nagbibigay-daan upang suriin ang interaksyon dito. Hindi tulad ng Stub na simpleng nagbabalik ng isang tinukoy na halaga, itinatala ng Mock ang katotohanan ng pagtawag ng method, ang mga ipinasa na argumento at ang bilang ng mga tawag. Ayon sa datos ng Mockito (2024), ang Mock ay ang pinakasikat na uri ng Test Double sa mga Java at Kotlin na proyekto, na ginagamit sa higit sa 70% ng unit-test ng mga mobile application.

Mga Pangunahing Punto

  • Mock — bagay na sumusuri ng interaksyon: aling mga method ang tinawag, sa anong mga argumento at ilang beses
  • Mockito — ang pinakasikat na library para sa paggawa ng Mock sa Java at Android na proyekto
  • MockK — alternatibo sa Mockito para sa Kotlin na may native na suporta para sa coroutine at sealed class
  • Behavior verification — pangunahing pagkakaiba ng Mock sa Stub: sinusuri ng Mock ang pag-uugali, hindi ang estado
  • Over-mocking — pangunahing Anti-Pattern: ang mock ay dapat lamang para sa panlabas na dependencies

Ano ang Mock?

Mock — ay isang bagay na ginawa ng mocking framework (Mockito, MockK, EasyMock), na ginagaya ang isang interface o klase at itinatala ang lahat ng tawag sa mga method nito. Ang developer ay nagtatakda ng mga inaasahan: ang method X ay tatawagin na may mga argumento Y at magbabalik ng Z. Pagkatapos isagawa ang test, sinusuri ng Mock kung ang mga inaasahan ay tumutugma sa mga aktwal na tawag.

Ang termino ay nagmula sa teatrikal na metapora ng Test Doubles: ang Mock ay isang “tagagaya” na hindi lamang nakatayo sa entablado (tulad ng Dummy), kundi gumaganap ng isang papel at sinusuri kung tama ang interaksyon dito. Kung ang code na sinusuri ay hindi tumawag sa method na inaasahan ng Mock, o tinawag ito na may maling mga argumento — ang test ay nabibigo na may mensahe tungkol sa nilabag na inaasahan.

Paano gumagana ang Mock

Ang Mock ay nilikha sa pamamagitan ng pabrika ng framework: mockk<MyInterface>() o Mockito.mock(MyClass.java). Ang framework ay lumilikha ng proxy-object na humahadlang sa lahat ng tawag sa method. Ang bawat tawag ay inihambing sa mga paunang itinakda na inaasahan (expectations). Kung ang tawag ay tumutugma sa inaasahan — ang itinakdang halaga ay ibinabalik. Kung hindi — ang Mock ay nagbabalik ng default na halaga o nagtatapon ng exception, depende sa configuration.

Kailan kinakailangan ang Mock

Mock ay kinakailangan kapag ang code na sinusuri ay nakikipag-ugnayan sa mga component na may side effects: pagpapadala ng data sa server, pagsusulat sa database, pag-log, analytics, nabigasyon, pagpapakita ng system dialogs. Kung walang Mock, ang mga interaksyong ito ay hindi masusuri nang hindi pinapatakbo ang tunay na imprastraktura. Ayon sa Google Testing Blog, ang Mock ay ang tanging paraan upang suriin na ang application ay talagang nagpadala ng analytics event nang hindi nagtaas ng test server.

Mock at Stub: detalyadong paghahambing

Ang pagkakaiba sa pagitan ng Mock at Stub ay isa sa mga pinaka-pinag-uusapang paksa sa pagsubok. Ang parehong uri ay pumapalit sa tunay na dependency, ngunit sa panimula na magkakaibang paraan.

KraytiryaMockStub
Pangunahing tanongTinawag ba ang method?Anong resulta ang ibinalik?
BeripikasyonPag-uugali (verify)Estado (assert)
Pagbabalik ng datosOpsyonalSapilitan
Halimbawaverify(analytics).logEvent("click")assertEquals(5, repository.getCount())
Kailan gagamitinSide effectsPagbabalik ng datos

Praktikal na patakaran: Mock o hindi

Isang simpleng test para pumili: tanungin ang iyong sarili — “kung tatanggalin ko ang linyang ito ng code, babagsak ba ang test?”. Kung ang test ay sumusuri sa ibinalik na halaga — kailangan ang Stub (pagsusuri sa pamamagitan ng assert). Kung ang test ay sumusuri kung ang code ay tumawag ng method na may tamang mga argumento — kailangan ang Mock (pagsusuri sa pamamagitan ng verify). Ang dichotomiyang ito ay sumusunod mula sa pattern na Command-Query Separation: ang mga method na nagbabago ng estado (commands) ay nangangailangan ng Mock; ang mga method na nagbabalik ng datos (queries) ay nangangailangan ng Stub.

Mockito at MockK: paghahambing ng mga library

Ang pagpili sa pagitan ng Mockito at MockK ay isa sa mga unang desisyon sa pag-setup ng test stack ng isang Android project sa Kotlin. Ang parehong library ay gumaganap ng parehong gawain, ngunit may iba't ibang approach sa Kotlin-specific na mga tampok.

Mockito: napatunayang klasiko

Mockito — ay ang de facto standard para sa mga Java project. Ang bersyon 5.x ay sumusuporta sa mock-object para sa final classes, static method at constructor salamat sa built-in na MockMaker. Para sa Kotlin project, ang Mockito ay nangangailangan ng karagdagang configuration: mockito-kotlin extension para sa pinahusay na syntax, mockito-inline para sa final classes. Hindi sinusuportahan ng Mockito ang Kotlin coroutine at suspend functions nang walang karagdagang adapters.

MockK: Kotlin-first approach

MockK ay ginawa partikular para sa Kotlin. Ito ay native na sumusuporta sa coroutine (coEvery, coVerify), sealed class, data class, object-singleton at extension functions. Ang syntax ng MockK ay gumagamit ng DSL na may lambda blocks, na natural na hitsura sa Kotlin code. Ang MockK ay maaari ring mag-mock ng mga property (property mocking) nang walang karagdagang configuration — ito ay mahalaga para sa Android project na gumagamit ng LiveData, StateFlow at Delegates.

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

Paghahambing ng pagganap

Ang mga benchmark (JVM Benchmark, 2024) ay nagpapakita na ang MockK ay lumilikha ng mock-object nang 15–20% mas mabilis kaysa Mockito para sa Kotlin project dahil sa direktang pagtatrabaho sa Kotlin bytecode, hindi Java Reflections. Para sa mga project na may libu-libong unit-test, ang pagkakaiba sa oras ng pagbuo ay maaaring kapansin-pansin: ang MockK ay nakakatipid ng 30–60 segundo sa buong pagtakbo ng test sa malalaking project.

Mga halimbawa ng Mock test sa Kotlin

Tatalakayin natin ang tatlong senaryo: pagsubok ng ViewModel na may Mock-dependencies, pagsubok ng UseCase na may beripikasyon ng API call at pagsubok ng coroutine na may coVerify.

Halimbawa 1: ViewModel na may Mock analytics

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

Halimbawa 2: UseCase na may asynchronous na beripikasyon

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

Halimbawa 3: beripikasyon ng argumento gamit ang ArgumentCaptor

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

Pinakamahusay na kasanayan sa Mock testing

Ang epektibong paggamit ng Mock sa mobile development ay nangangailangan ng disiplina. Ang paglabag sa mga patakarang ito ay ginagawang marupok na hadlang ang mga test na nasisira sa bawat refactoring.

Mock lamang ang panlabas na hangganan ng application

Mahigpit na patakaran: Ang Mock ay ginagawa lamang para sa mga dependency na tumatawid sa hangganan ng application: API clients, database, file system, system services (LocationManager, BluetoothAdapter, Camera). Ang mga panloob na klase ng application — domain entities, Value Object, simpleng utilities — ay hindi dapat palitan ng Mock. Ang kanilang pag-uugali ay sinusuri sa pamamagitan ng tunay na bagay.

Isang assert/verify bawat test

Ang bawat test ay dapat maglaman ng eksaktong isang lohikal na pagsusuri — alinman sa verify (para sa Mock), o assert (para sa Stub). Huwag paghaluin ang pagsusuri ng estado at pag-uugali sa isang test. Kung kailangan suriin pareho ang API call at ang resulta — gumawa ng dalawang magkahiwalay na test na may magkaibang pangalan. Ang patakarang ito, na kilala bilang “isang assert bawat test”, ay nagmula sa mga rekomendasyon ni Kent Beck (2002).

  • Gamitin ang relaxUnitFun = true sa MockK para sa mga method na nagbabalik ng Unit — kung hindi, ang Mock ay magtatapon ng exception sa hindi inilarawang tawag
  • Limitahan ang verify sa mga kritikal na tawag lamang — huwag i-verify ang bawat getter at setter, ito ay ginagawang marupok ang test
  • Ilapat ang ArgumentMatchers nang may kahulugan — ang any() ay nagtatago ng mahahalagang detalye kung ang argumento ay kritikal para sa business logic
  • Huwag abusuhin ang verifyNoMoreInteractions — ang method na ito ay ginagawang hindi kinakailangang mahigpit ang test sa anumang pagbabago sa production code
  • Gamitin ang @MockkAnnotations para sa awtomatikong pagsisimula ng Mock-object — binabawasan nito ang boilerplate at pinapabuti ang pagiging madaling mabasa

Mga advanced na pamamaraan ng Mock testing

Bukod sa pangunahing mocking, may mga advanced na pamamaraan na lumulutas ng mga tiyak na gawain sa mobile development: pagsubok ng multi-threading, pagsusuri ng estado ng Flow at partial mocking ng mga tunay na bagay.

Partial Mock gamit ang spyK

Spy (o partial mock) ay nagbibigay-daan sa paglikha ng bagay na nagtatalaga ng mga tawag sa tunay na implementasyon, ngunit nagpapahintulot sa pag-override ng mga indibidwal na method. Sa MockK, ang spyk ay nilikha batay sa tunay na instance ng klase: val repo = spyk(InMemoryUserRepository()). Ang mga tawag kung saan itinakda ang mga inaasahan sa pamamagitan ng every ay dumadaan sa Mock; ang iba — sa pamamagitan ng tunay na bagay. Ang Spy ay lalong kapaki-pakinabang para sa pagsubok ng legacy-code kung saan ang dependency injection ay hindi pa naipatupad, at kailangan lamang i-override ang isang method.

Pagsubok ng StateFlow gamit ang Turbine

Sa mga modernong Android project sa Jetpack Compose, ang ViewModel ay naglalantad ng estado sa pamamagitan ng StateFlow. Ang MockK ay nagbibigay-daan sa mocking ng Flow dependencies, at ang Turbine library ay nagpapasimple ng beripikasyon ng emisyon. Ang klasikong pattern: MockK para sa UseCase na nagbabalik ng Flow, Turbine para sa beripikasyon ng ViewModel emission. Ang stack na ito ay inirerekomenda ng dokumentasyon ng Android Testing (Google, 2024) para sa mga project sa Kotlin Coroutines.

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

Mga Madalas Itanong

Paano naiiba ang Mock sa Mockito?

Mock — ay isang konsepto, uri ng Test Double na sumusuri ng pag-uugali. Mockito — ay isang library para sa paggawa ng Mock-object sa Java at Android. Iba pang library: MockK (Kotlin), EasyMock (Java), Cuckoo (iOS).

Paano gumagana ang Mock sa Kotlin coroutine?

Para sa pagsubok ng suspend functions gamit ang Mock, gamitin ang MockK (coEvery / coVerify) o Mockito na may mockito-kotlin. Ang MockK ay sumusuporta sa coroutine nang native: ang coEvery ay tumutukoy sa pag-uugali ng suspend function, ang coVerify ay sumusuri sa tawag nito sa loob ng coroutine. Lahat ng suspend tawag ay dapat isagawa sa loob ng runTest (kotlinx-coroutines-test).

Maaari bang magbalik ang Mock ng iba't ibang halaga sa paulit-ulit na tawag?

Oo. Sa MockK para dito ginagamit ang returnsMany: every { api.getData() } returnsMany listOf(response1, response2). Sa Mockito — ang chain na thenReturn(value1).thenReturn(value2). Ito ay kapaki-pakinabang para sa pagsubok ng pag-uugali sa sunud-sunod na tawag na may iba't ibang tugon.

Paano linisin ang estado ng Mock sa pagitan ng mga test?

Sa MockK gamitin ang annotation na @MockK na may field na relaxed = true at tawagin ang clearMocks(mock) sa @After method. Sa MockitoMockito.reset(mock). Pinakamahusay na kasanayan: gumawa ng bagong Mock para sa bawat test sa pamamagitan ng @Before upang alisin ang impluwensya sa pagitan ng mga test.

Paano hinahawakan ng Mock ang sealed class sa Kotlin?

MockK ay wastong gumagana sa sealed class: every { useCase() } returns Result.Success(data). Mockito ay hindi direktang sumusuporta sa sealed class, nangangailangan ng mga paraan para makaiwas. Ito ay isa sa mga dahilan kung bakit para sa Kotlin project ay inirerekomenda ang MockK sa halip na Mockito.

Buod

  • Mock — uri ng Test Double na sumusuri ng pag-uugali (verify), hindi estado (assert) ng dependencies
  • Mockito — standard para sa Java/Android, MockK — Kotlin-first na pagpili na may suporta para sa coroutine at sealed class
  • Pangunahing patakaran: Mock para sa panlabas na hangganan (network, DB, system services), tunay na bagay para sa panloob na klase
  • Over-mocking — pangunahing Anti-Pattern: labis na pagpapalit ng dependencies ay ginagawang marupok at hindi gaanong kapaki-pakinabang ang test
  • Isang test — isang lohikal na pagsusuri: verify para sa Mock o assert para sa Stub, ngunit hindi pareho sa isang test
  • ArgumentCaptor / slot — tamang paraan ng pagsusuri ng mga argumento ng Mock tawag sa halip na bulag na any()
  • Ang MockK ay inirerekomenda para sa Kotlin project: ang coEvery at coVerify ay native na gumagana sa coroutine nang walang karagdagang adapters

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din