Stub: apa itu, jenis, dan penerapannya dalam pengujian

Penulis: IT Sectr Diterbitkan: 2026-04-10 Waktu membaca: 9 mnt

Stub (pengganti, tiruan) — objek pengujian yang mengembalikan respons yang telah ditentukan sebelumnya pada pemanggilan metode, bukan implementasi nyata. Dalam pengembangan seluler, stub mengisolasi modul yang diuji dari permintaan jaringan, basis data, dan sistem file, memungkinkan pemeriksaan logika tanpa konfigurasi lingkungan. Tidak seperti mock, stub tidak memverifikasi perilaku — ia hanya menyediakan data. Selengkapnya di artikel Martin Fowler tentang test doubles.

Poin Utama

  • Stub — pengganti yang mengembalikan nilai yang ditentukan pada pemanggilan metode tanpa logika
  • Isolasi — stub menonaktifkan ketergantungan nyata: API, basis data, file, sensor
  • Perbedaan dari Mock — stub tidak memverifikasi pemanggilan, ia hanya mengganti respons
  • Android — MockWebServer (OkHttp) sebagai stub untuk HTTP, MockK.constantAnswer untuk Kotlin
  • iOS — OCMock dan protokol Swift dengan implementasi pengujian sebagai stub

Apa itu Stub dan apa bedanya dengan test doubles lainnya?

Stub — adalah objek pengganti yang menggantikan ketergantungan nyata dalam pengujian dan mengembalikan nilai yang telah ditentukan pada pemanggilan tertentu. Istilah ini diperkenalkan dalam klasifikasi Gerard Meszaros (2007) dalam buku “xUnit Test Patterns”. Stub termasuk dalam kategori test doubles — objek yang menggantikan komponen nyata selama pengujian. Tujuan utama stub adalah menyediakan data yang dapat diprediksi untuk blok yang diuji, menghilangkan ketidakpastian sistem eksternal.

Prinsip kerja — pengujian mengonfigurasi stub sebelum eksekusi: “ketika metode getUsers() dipanggil, kembalikan daftar pengguna ini”. Stub tidak mengandung logika bisnis, tidak memeriksa urutan pemanggilan, dan tidak mencatat riwayat akses. Ia hanya berdiri di tempat komponen nyata dan mengembalikan apa yang diperintahkan. Dalam konteks pengujian Android, ini berarti klien OkHttp tidak membuat permintaan nyata ke server, melainkan menerima respons dari MockWebServer yang dikonfigurasi sebagai stub.

  • Stub — mengembalikan data, tidak memeriksa pemanggilan
  • Mock — mengembalikan data dan memverifikasi perilaku (verify)
  • Fake — implementasi sederhana yang berfungsi dengan logika nyata
  • Spy — membungkus objek nyata, mencatat pemanggilan
  • Dummy — dikirimkan tetapi tidak digunakan (null, objek kosong)

Kapan menggunakan — stub optimal untuk menguji lapisan UI (ViewModel, Presenter) dan logika bisnis (UseCase, Interactor), di mana perlu memeriksa reaksi terhadap data tertentu: daftar kosong, server mengembalikan kesalahan 500, token kedaluwarsa. Setiap kasus di mana pengujian memerlukan status input tertentu adalah tugas untuk stub. Untuk setiap skenario pengujian, konfigurasi stub sendiri dibuat, yang membuat pengujian dapat dibaca dan diprediksi.

Klasifikasi test doubles menurut Meszaros

Gerard Meszaros (2007) dalam buku “xUnit Test Patterns” mengidentifikasi lima jenis test doubles: dummy, stub, spy, mock, fake. Setiap jenis menyelesaikan tugasnya sendiri. Dummy — dikirimkan tetapi tidak digunakan. Stub — mengembalikan data. Spy — mencatat pemanggilan. Mock — memverifikasi perilaku. Fake — berisi logika yang disederhanakan. Pemahaman tentang klasifikasi ini membantu pengembang memilih alat yang tepat untuk setiap skenario pengujian.

Di mana stub digunakan dalam pengujian aplikasi seluler

Stub untuk permintaan jaringan

Permintaan jaringan — skenario paling umum penggunaan stub. Aplikasi melakukan panggilan HTTP ke API, dan dalam pengujian perlu memeriksa reaksi terhadap berbagai respons: JSON berhasil, kesalahan 401 (tidak sah), waktu habis, larik kosong. MockWebServer (OkHttp) di Android dan URLProtocol (iOS) bertindak sebagai stub, mengembalikan respons HTTP yang telah ditentukan tanpa koneksi nyata ke server. Ini mempercepat pengujian dari detik menjadi milidetik.

Basis data — Room (Android) dan CoreData (iOS) memiliki varian in-memory, tetapi konfigurasinya tetap memakan waktu. Stub alih-alih repositori mengembalikan daftar Entity yang sudah disiapkan tanpa menyentuh basis data. Ini sangat efektif untuk menguji ViewModel, di mana perlu memeriksa pengurutan, pemfilteran, atau transformasi data. Pengujian berjalan dalam milidetik terlepas dari volume data.

Layanan sistem — LocationManager, SensorManager, SharedPreferences memerlukan perangkat nyata atau emulator. Stub untuk LocationProvider mengembalikan koordinat yang ditentukan, untuk SensorManager — nilai akselerometer tetap. Di iOS, analognya adalah CLLocationManager dengan implementasi delegasi pengujian. Tanpa stub, pengujian semacam itu memerlukan perangkat fisik dengan kondisi tertentu.

Sistem file dan cache — memuat gambar, menyimpan respons dalam cache, bekerja dengan file konfigurasi — semua operasi ini bergantung pada status disk. Stub untuk FileManager atau ImageCache mengembalikan sukses/gagal tanpa membaca file nyata. Ini menghilangkan kegagalan pengujian palsu karena ketidakcocokan jalur atau izin di berbagai mesin pengembang.

Stub vs Mock vs Fake: perbedaan utama

Pembagian tanggung jawab — tiga jenis test doubles menyelesaikan tugas yang berbeda. Stub: “beri saya data”. Mock: “periksa apakah saya dipanggil”. Fake: “saya bekerja seperti asli, hanya lebih sederhana”. Perbedaan ini sangat penting untuk keterbacaan pengujian: jika pengujian menggunakan mock di tempat yang membutuhkan stub, ia akan kelebihan beban dengan panggilan verify yang tidak terkait dengan skenario yang diuji.

KarakteristikStubMockFake
TujuanMenyediakan dataMemverifikasi interaksiImplementasi sederhana
LogikaTidakTidakYa (tapi sederhana)
VerifikasiTidakYa (verify)Tidak langsung (melalui status)
FleksibilitasRendah — respons tetapSedangTinggi — logika beradaptasi
KecepatanMaksimalTinggiSedang
ContohMockWebServer mengembalikan JSONMockito.verify(repository).save()InMemoryRepository dengan HashMap

Aturan praktis — jika pengujian memeriksa data apa yang diterima komponen yang diuji — gunakan stub. Jika pengujian memeriksa apakah komponen memanggil metode ketergantungan dengan argumen yang benar — gunakan mock. Jika Anda hanya ingin mengganti basis data dengan tabel hash — ini adalah fake. Mencampur jenis dalam satu pengujian membuatnya rapuh: saat implementasi berubah, baik stub maupun logika verify harus ditulis ulang.

Antipola: Stub dengan verify

Stub dengan verify — kesalahan umum ketika pengembang mengonfigurasi stub dan kemudian menambahkan verify(stub).method(). Stub menurut definisi tidak boleh diverifikasi — untuk verifikasi ada mock. Jika Anda perlu memeriksa bahwa metode dipanggil dengan argumen tertentu, gunakan Mockito.mock() alih-alih Mockito.stub(). Pemisahan ini menjaga niat pengujian tetap jelas bagi pengembang lain.

Implementasi stub di Android dengan MockWebServer dan MockK

MockWebServer — pustaka OkHttp untuk membuat stub HTTP di Android dan JVM. Pustaka ini menjalankan server HTTP lokal pada port yang ditentukan yang mencegat permintaan klien OkHttp dan mengembalikan respons yang telah ditentukan. Konfigurasi membutuhkan tiga baris: buat server, masukkan respons ke antrian (enqueue), jalankan. Pengujian dapat memasukkan beberapa respons secara berurutan ke antrian untuk skenario dengan paginasi atau percobaan ulang.

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 — alternatif Mockito untuk Kotlin dengan dukungan first-class untuk coroutine, fungsi ekstensi, dan kelas sealed. Stub di MockK dibuat melalui coEvery (untuk fungsi suspend) dan every (untuk fungsi biasa). Tidak seperti MockWebServer, MockK mengganti metode ketergantungan individual, bukan seluruh lapisan HTTP. Ini nyaman untuk pengujian unit UseCase atau Interactor, di mana ketergantungannya adalah abstraksi repositori.

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 — untuk pengujian integrasi, gunakan MockWebServer (mencegat HTTP nyata), untuk pengujian unit — MockK (mengganti antarmuka). Jangan mengganti apa yang tidak Anda uji: jika pengujian memeriksa Repository, jangan mengganti klien OkHttp di dalamnya — gunakan MockWebServer nyata di tingkat HTTP. Aturan ini menjaga pengujian tetap relevan dan mengurangi kerapuhan saat refaktorisasi.

Implementasi stub di iOS dengan OCMock dan protokol

Protokol Swift sebagai stub — dalam pendekatan asli iOS, stub diimplementasikan dengan menyisipkan struktur pengujian yang sesuai dengan protokol ketergantungan. Alih-alih NetworkService nyata, pengujian menerima StubNetworkService yang mengembalikan data tetap. Swift adalah bahasa dengan pengetikan statis, sehingga stub harus sesuai dengan protokol yang sama dengan layanan nyata. Kompilator menjamin bahwa stub mengimplementasikan semua metode yang diperlukan.

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 untuk Objective-C — pustaka untuk membuat stub dan mock di proyek iOS lama. OCMock mendukung metode stub dengan argumen dan nilai kembalian. Proyek modern di Swift lebih memilih pendekatan berbasis protokol dengan stub manual — ini memberikan kontrol atas setiap metode dan tidak memerlukan ketergantungan eksternal. OCMock tetap menjadi pilihan untuk proyek di mana protokolisasi semua ketergantungan tidak layak secara ekonomi.

URLProtocol untuk stub HTTP — mekanisme sistem iOS untuk mencegat permintaan jaringan melalui subkelas URLProtocol. Pengujian mendaftarkan URLProtocol kustom yang mencegat URLSession dan mengembalikan respons stub. Keuntungan dibandingkan stub manual: arsitektur aplikasi tidak perlu diubah — URLSession tetap nyata, tetapi data diganti di tingkat protokol. Kekurangan: lebih sulit di-debug daripada layanan stub eksplisit.

Pertanyaan yang Sering Diajukan

Apa perbedaan Stub dengan Mock?

Stub mengembalikan data yang telah ditentukan dan tidak memeriksa fakta pemanggilan. Mock selain itu memverifikasi bahwa metode dipanggil dengan argumen yang benar (verify). Stub menjawab pertanyaan “apa yang harus dikembalikan”, Mock — pertanyaan “apakah dipanggil”. Gunakan stub untuk memeriksa status, mock — untuk memeriksa interaksi.

Kapan menggunakan Fake alih-alih Stub?

Fake diperlukan ketika pengujian membutuhkan implementasi yang berfungsi (meskipun sederhana) — misalnya, basis data in-memory alih-alih Room. Stub cocok untuk skenario tunggal dengan data yang telah ditentukan. Jika Anda mengulangi stub yang sama dalam 10 pengujian — kemungkinan besar Anda membutuhkan Fake. Fake mengurangi duplikasi karena logika hidup dalam satu kelas.

Bisakah metode statis di-stub?

Di Android — MockK untuk objek Kotlin (object) mendukung mockkObject(), termasuk metode statis kelas Java melalui mockkStatic(). Di iOS — metode statis Swift tidak bisa di-stub secara langsung; gunakan protokol dan DI untuk mengganti panggilan static dengan metode instance protokol. Stub statis adalah utang teknis dan harus dihindari dalam kode baru.

Bagaimana cara men-stub permintaan jaringan di Android?

Gunakan MockWebServer (OkHttp) — ia bekerja sebagai server HTTP lokal yang memasukkan respons ke antrian (enqueue). Untuk Retrofit, cukup mengganti URL dasar ke localhost:8080. Untuk Ktor, gunakan MockEngine — mekanisme bawaan untuk mengganti HttpStatement. Kedua pendekatan bekerja tanpa internet nyata dan memberikan kendali penuh atas kode status, body, dan header respons.

Stub vs Spy — apa bedanya?

Spy membungkus objek nyata dan mencatat pemanggilan, sedangkan Stub sepenuhnya mengganti objek dengan respons tetap. Spy memungkinkan penggunaan sebagian implementasi nyata (metode lain berfungsi seperti sebelumnya), sedangkan stub tidak. Jika Anda perlu memeriksa bahwa metode dipanggil, tetapi sebagian logika harus dijalankan — gunakan spy, bukan stub.

Kesimpulan

  • Stub — objek pengganti yang mengembalikan respons yang telah ditentukan pada pemanggilan metode selama pengujian
  • Isolasi ketergantungan — stub menggantikan permintaan jaringan, basis data, layanan sistem, dan sistem file
  • Perbedaan dari Mock — stub tidak memverifikasi pemanggilan, ia hanya mengembalikan data tanpa pemeriksaan perilaku
  • Alat Android — MockWebServer untuk HTTP, MockK untuk antarmuka Kotlin dengan dukungan coroutine
  • Alat iOS — stub berbasis protokol di Swift, URLProtocol untuk HTTP, OCMock untuk Objective-C
  • Jangan campur peran — jangan tambahkan verify ke stub, gunakan mock untuk verifikasi pemanggilan
  • Stub + MockWebServer — pendekatan standar untuk pengujian integrasi tanpa server nyata

Kami akan mengembangkan aplikasi seluler turnkey

IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.

Diskusikan proyek

Baca juga