Stub: ano ito, mga uri at aplikasyon sa pagsubok

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

Stub (pamalit, test stub) — isang test object na nagbabalik ng mga paunang natukoy na tugon sa mga tawag ng method sa halip na tunay na implementasyon. Sa mobile development, ang mga stub ay naghihiwalay sa sinusubok na module mula sa mga network request, database, at file system, na nagpapahintulot sa pagsusuri ng lohika nang walang pag-configure ng kapaligiran. Hindi tulad ng mock, ang stub ay hindi nagbe-verify ng behavior — nagbibigay lamang ito ng data. Higit pang detalye sa artikulo ni Martin Fowler tungkol sa test doubles.

Mga Pangunahing Punto

  • Stub — pamalit na nagbabalik ng mga itinakdang halaga sa mga tawag ng method nang walang lohika
  • Pagbubukod — pinapatay ng mga stub ang mga tunay na dependency: API, database, file, sensor
  • Pagkakaiba sa Mock — hindi bine-verify ng stub ang mga tawag, pinapalitan lamang nito ang tugon
  • Android — MockWebServer (OkHttp) bilang stub para sa HTTP, MockK.constantAnswer para sa Kotlin
  • iOS — OCMock at Swift protocols na may test implementations bilang mga stub

Ano ang Stub at paano ito naiiba sa iba pang test doubles?

Stub — ay isang pamalit na bagay na pumapalit sa tunay na dependency sa test at nagbabalik ng mga paunang itinakdang halaga sa mga partikular na tawag. Ang termino ay ipinakilala sa klasipikasyon ni Gerard Meszaros (2007) sa aklat na “xUnit Test Patterns”. Ang Stub ay kabilang sa kategorya ng test doubles — mga bagay na pumapalit sa mga tunay na bahagi sa panahon ng pagsubok. Ang pangunahing layunin ng stub ay magbigay ng mahuhulaan na data sa sinusubok na bloke, na inaalis ang kawalan ng katiyakan ng mga panlabas na sistema.

Prinsipyo ng paggana — kino-configure ng test ang stub bago ang pagpapatupad: “kapag ang method na getUsers() ay tinawag, ibalik ang listahang ito ng mga user”. Ang Stub ay hindi naglalaman ng business logic, hindi sinusuri ang pagkakasunud-sunod ng mga tawag, at hindi nagtatala ng kasaysayan. Ito ay nakatayo lamang sa lugar ng tunay na bahagi at ibinabalik ang sinabi dito. Sa konteksto ng Android testing, nangangahulugan ito na ang OkHttp client ay hindi gumagawa ng tunay na request sa server, sa halip ay tumatanggap ng tugon mula sa MockWebServer na na-configure bilang stub.

  • Stub — nagbabalik ng data, hindi nagbe-verify ng mga tawag
  • Mock — nagbabalik ng data at nagbe-verify ng behavior (verify)
  • Fake — gumaganang pinasimpleng implementasyon na may tunay na lohika
  • Spy — bumabalot sa tunay na bagay, nagtatala ng mga tawag
  • Dummy — ipinapasa ngunit hindi ginagamit (null, walang laman na bagay)

Kailan gagamitin — ang mga stub ay pinakamainam para sa pagsubok ng UI layer (ViewModel, Presenter) at business logic (UseCase, Interactor), kung saan kailangang suriin ang reaksyon sa partikular na data: walang laman na listahan, nagbalik ng error 500 ang server, nag-expire ang token. Bawat kaso kung saan ang test ay nangangailangan ng partikular na input state ay isang gawain para sa stub. Para sa bawat test scenario, nilikha ang sariling configuration ng stub, na ginagawang nababasa at mahuhulaan ang mga test.

Klasipikasyon ng test doubles ayon kay Meszaros

Gerard Meszaros (2007) sa aklat na “xUnit Test Patterns” ay nagtukoy ng limang uri ng test doubles: dummy, stub, spy, mock, fake. Bawat uri ay lumulutas ng sarili nitong gawain. Dummy — ipinapasa ngunit hindi ginagamit. Stub — nagbabalik ng data. Spy — nagtatala ng mga tawag. Mock — nagbe-verify ng behavior. Fake — naglalaman ng pinasimpleng lohika. Ang pag-unawa sa klasipikasyong ito ay tumutulong sa developer na pumili ng tamang kasangkapan para sa bawat test scenario.

Saan ginagamit ang mga stub sa pagsubok ng mga mobile application

Mga stub para sa mga network request

Mga network request — ang pinakakaraniwang scenario ng paggamit ng mga stub. Ang application ay gumagawa ng HTTP calls sa API, at sa test kailangang suriin ang reaksyon sa iba't ibang tugon: matagumpay na JSON, error 401 (hindi awtorisado), timeout, walang laman na array. Ang MockWebServer (OkHttp) sa Android at URLProtocol (iOS) ay gumaganap bilang mga stub, na nagbabalik ng mga paunang natukoy na HTTP na tugon nang walang tunay na koneksyon sa server. Pinapabilis nito ang mga test mula segundo hanggang millisecond.

Database — ang Room (Android) at CoreData (iOS) ay may mga in-memory variant, ngunit ang pag-configure sa mga ito ay nangangailangan pa rin ng oras. Ang Stub sa halip ng repository ay nagbabalik ng mga paunang handa na listahan ng Entity nang hindi ginagalaw ang database. Ito ay lalong epektibo para sa pagsubok ng ViewModel, kung saan kailangang suriin ang pag-uuri, pag-filter, o pagbabago ng data. Ang test ay tumatakbo sa millisecond anuman ang dami ng data.

Mga serbisyo ng system — ang LocationManager, SensorManager, SharedPreferences ay nangangailangan ng tunay na device o emulator. Ang Stub para sa LocationProvider ay nagbabalik ng mga itinakdang coordinate, para sa SensorManager — mga nakapirming halaga ng accelerometer. Sa iOS, ang analog ay CLLocationManager na may test implementation ng delegate. Kung walang mga stub, ang mga ganitong test ay nangangailangan ng pisikal na device na may partikular na mga kondisyon.

File system at cache — pag-load ng mga imahe, pag-cache ng mga tugon, paggawa sa mga configuration file — lahat ng operasyong ito ay nakadepende sa estado ng disk. Ang Stub para sa FileManager o ImageCache ay nagbabalik ng tagumpay/kabiguan nang hindi nagbabasa ng mga tunay na file. Inaalis nito ang mga maling pagbagsak ng test dahil sa hindi pagkakatugma ng mga path o pahintulot sa iba't ibang makina ng mga developer.

Stub vs Mock vs Fake: mga pangunahing pagkakaiba

Paghahati ng responsibilidad — tatlong uri ng test doubles ay lumulutas ng iba't ibang gawain. Stub: “bigyan mo ako ng data”. Mock: “suriin kung ako ay tinawag”. Fake: “gumagana ako tulad ng tunay, mas simple lang”. Ang pagkakaiba ay kritikal para sa pagiging nababasa ng mga test: kung ang test ay gumagamit ng mock kung saan kailangan ang stub, ito ay nabibigatan ng mga verify call na hindi nauugnay sa sinusubok na scenario.

KatangianStubMockFake
LayuninMagbigay ng dataSuriin ang interaksyonPinasimpleng implementasyon
LohikaWalaWalaMayroon (ngunit pinasimple)
BeripikasyonWalaMayroon (verify)Hindi direkta (sa pamamagitan ng estado)
FlexibilityMababa — nakapirming tugonKatamtamanMataas — umaangkop ang lohika
BilisPinakamataasMataasKatamtaman
HalimbawaMockWebServer nagbabalik ng JSONMockito.verify(repository).save()InMemoryRepository na may HashMap

Praktikal na patakaran — kung sinusuri ng test kung anong data ang natanggap ng sinusubok na component — gumamit ng stub. Kung sinusuri ng test kung tinawag ng component ang dependency method na may tamang argumento — gumamit ng mock. Kung gusto mo lang palitan ang database ng hash table — ito ay fake. Ang paghahalo ng mga uri sa isang test ay ginagawa itong marupok: kapag nagbago ang implementasyon, kakailanganing muling isulat ang parehong stub at verify logic.

Antipattern: Stub na may verify

Stub na may verify — isang karaniwang pagkakamali kapag ang developer ay nagko-configure ng stub at pagkatapos ay nagdaragdag ng verify(stub).method(). Ang Stub ay hindi dapat i-verify ayon sa depinisyon — para sa beripikasyon ay mayroong mock. Kung kailangan mong suriin na ang method ay tinawag na may partikular na argumento, gamitin ang Mockito.mock() sa halip na Mockito.stub(). Ang paghihiwalay na ito ay nagpapanatili ng intensyon ng test na malinaw para sa iba pang mga developer.

Implementasyon ng mga stub sa Android gamit ang MockWebServer at MockK

MockWebServer — OkHttp library para sa paggawa ng HTTP stubs sa Android at JVM. Ito ay nagpapagana ng lokal na HTTP server sa isang tinukoy na port na humaharang sa mga request ng OkHttp client at nagbabalik ng mga paunang natukoy na tugon. Ang pag-configure ay tumatagal ng tatlong linya: lumikha ng server, i-enqueue ang tugon, patakbuhin. Ang test ay maaaring mag-enqueue ng maraming tugon nang sunud-sunod para sa mga scenario na may pagination o pagsubok muli.

kotlin
class UserRepositoryTest {

    private val server = MockWebServer()

    fun setup() {
        server.start(8080)
        val client = OkHttpClient.Builder()
            .readTimeout(1, TimeUnit.SECONDS)
            .build()
    }

    fun test_user_list_success() {
        val json = "[{\"id\":1,\"name\":\"Alice\"}]"
        server.enqueue(MockResponse()
            .setBody(json)
            .setResponseCode(200)
        )
        val result = repository.getUsers()
        assertEquals(1, result.size)
    }

    fun teardown() {
        server.shutdown()
    }
}

MockK — alternatibo sa Mockito para sa Kotlin na may first-class na suporta para sa coroutines, extension functions, at sealed classes. Ang mga stub sa MockK ay nilikha sa pamamagitan ng coEvery (para sa suspend functions) at every (para sa ordinaryong functions). Hindi tulad ng MockWebServer, pinapalitan ng MockK ang mga indibidwal na dependency method, hindi ang buong HTTP layer. Ito ay maginhawa para sa unit test ng UseCase o Interactor, kung saan ang mga dependency ay mga abstraksyon ng repositories.

kotlin
interface UserRepository {
    suspend fun getUsers(): List<User>
}

class GetUsersUseCaseTest {

    private val repo = mockk<UserRepository>()

    private val useCase = GetUsersUseCase(repo)

    fun test_empty_list() = runTest {
        coEvery { repo.getUsers() } returns emptyList()

        val result = useCase.invoke()

        assertTrue(result.isEmpty())
        coVerify(exactly = 1) { repo.getUsers() }
    }
}

Best practice — para sa integration tests gamitin ang MockWebServer (humaharang sa tunay na HTTP), para sa unit tests — MockK (pumapalit sa interfaces). Huwag palitan ang hindi mo sinusubok: kung sinusuri ng test ang Repository, huwag palitan ang OkHttp client sa loob nito — gamitin ang tunay na MockWebServer sa antas ng HTTP. Ang patakarang ito ay nagpapanatili ng mga test na may kaugnayan at nagbabawas ng pagiging marupok sa refactoring.

Implementasyon ng mga stub sa iOS gamit ang OCMock at protocols

Swift protocols bilang mga stub — sa iOS-native na approach, ang stub ay ipinapatupad sa pamamagitan ng paglalagay ng test structure na sumusunod sa dependency protocol. Sa halip ng tunay na NetworkService, ang test ay tumatanggap ng StubNetworkService na nagbabalik ng nakapirming data. Ang Swift ay isang wika na may static typing, kaya ang stub ay dapat sumunod sa parehong protocol gaya ng tunay na serbisyo. Ginagarantiyahan ng compiler na ang stub ay nagpapatupad ng lahat ng kinakailangang method.

swift
protocol NetworkServiceProtocol {
    func fetchUsers() async throws -> [User]
}

struct StubNetworkService: NetworkServiceProtocol {
    let result: Result<[User], Error>

    func fetchUsers() async throws -> [User] {
        try result.get()
    }
}

final class UsersViewModelTests: XCTestCase {
    func test_success_state() async {
        let stub = StubNetworkService(
            result: .success([User(name: "Alice")])
        )
        let vm = UsersViewModel(service: stub)
        await vm.load()
        XCTAssertEqual(vm.users.count, 1)
    }
}

OCMock para sa Objective-C — library para sa paggawa ng mga stub at mock sa legacy iOS projects. Sinusuportahan ng OCMock ang stub methods na may argumento at return value. Mas gusto ng mga modernong proyekto sa Swift ang protocol-based approach na may manual stubs — nagbibigay ito ng kontrol sa bawat method at hindi nangangailangan ng mga panlabas na dependency. Ang OCMock ay nananatiling opsyon para sa mga proyekto kung saan ang pag-protocolize ng lahat ng dependency ay hindi praktikal sa ekonomiya.

URLProtocol para sa HTTP stubs — mekanismo ng system ng iOS para sa pagharang ng mga network request sa pamamagitan ng URLProtocol subclass. Nagrerehistro ang test ng custom na URLProtocol na humaharang sa URLSession at nagbabalik ng stub responses. Kalamangan kumpara sa manual stubs: hindi kailangang baguhin ang arkitektura ng application — nananatiling tunay ang URLSession, ngunit ang data ay pinapalitan sa antas ng protocol. Kakulangan: mas mahirap i-debug kaysa sa isang tahasang stub service.

Mga Madalas Itanong

Paano naiiba ang Stub sa Mock?

Stub ay nagbabalik ng paunang natukoy na data at hindi sinusuri ang katotohanan ng tawag. Ang Mock ay dagdag na nagbe-verify na ang method ay tinawag na may tamang argumento (verify). Ang Stub ay sumasagot sa tanong na “ano ang ibabalik”, Mock — sa tanong na “tinawag ba ito”. Gamitin ang stub para sa pagsusuri ng estado, mock — para sa pagsusuri ng interaksyon.

Kailan gagamitin ang Fake sa halip ng Stub?

Fake ay kinakailangan kapag ang test ay nangangailangan ng gumaganang (kahit pinasimple) implementasyon — halimbawa, in-memory database sa halip ng Room. Ang Stub ay angkop para sa mga solong scenario na may paunang natukoy na data. Kung inuulit mo ang parehong stub sa 10 tests — malamang kailangan mo ng Fake. Binabawasan ng Fake ang pagdodoble dahil ang lohika ay nabubuhay sa isang klase.

Maaari bang i-stub ang mga static na method?

Sa Android — MockK para sa Kotlin objects (object) ay sumusuporta sa mockkObject(), kabilang ang mga static method ng Java classes sa pamamagitan ng mockkStatic(). Sa iOS — ang mga static method ng Swift ay hindi direktang na-st-stub; gumamit ng protocols at DI upang palitan ang static call ng instance method ng protocol. Ang mga static stub ay technical debt at dapat iwasan sa bagong code.

Paano i-stub ang mga network request sa Android?

Gamitin ang MockWebServer (OkHttp) — ito ay gumagana bilang lokal na HTTP server na nag-e-enqueue ng mga tugon. Para sa Retrofit, sapat na palitan ang base URL sa localhost:8080. Para sa Ktor, gamitin ang MockEngine — ang built-in na mekanismo para sa pagpapalit ng HttpStatement. Ang parehong approach ay gumagana nang walang tunay na internet at nagbibigay ng buong kontrol sa status code, body, at headers ng tugon.

Stub vs Spy — ano ang pagkakaiba?

Spy ay bumabalot sa tunay na bagay at nagtatala ng mga tawag, samantalang ang Stub ay ganap na pinapalitan ang bagay ng mga nakapirming tugon. Ang Spy ay nagpapahintulot ng bahagyang paggamit ng tunay na implementasyon (ang iba pang method ay gumagana tulad ng dati), at ang stub — hindi. Kung kailangan mong suriin na ang method ay tinawag, ngunit ang bahagi ng lohika ay dapat isagawa — gumamit ng spy, hindi stub.

Buod

  • Stub — pamalit na bagay na nagbabalik ng mga paunang natukoy na tugon sa mga tawag ng method sa panahon ng pagsubok
  • Pagbubukod ng mga dependency — pinapalitan ng mga stub ang mga network request, database, system services, at file system
  • Pagkakaiba sa Mock — hindi bine-verify ng stub ang mga tawag, nagbabalik lamang ito ng data nang walang pagsusuri ng behavior
  • Mga tool sa Android — MockWebServer para sa HTTP, MockK para sa Kotlin interfaces na may suporta sa coroutine
  • Mga tool sa iOS — protocol-based stubs sa Swift, URLProtocol para sa HTTP, OCMock para sa Objective-C
  • Huwag paghaluin ang mga papel — huwag magdagdag ng verify sa stub, gumamit ng mock para sa beripikasyon ng tawag
  • Stub + MockWebServer — karaniwang approach para sa integration tests nang walang tunay na server

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