Fake — apa itu, tujuan dan cara menggunakannya dalam pengujian

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

Fake (feik) — implementasi dependensi yang disederhanakan dan berfungsi, berperilaku seperti komponen asli, tetapi menggunakan penyimpanan in-memory atau mekanisme ringan lainnya, bukan infrastruktur produksi. Berbeda dengan stub, fake berisi logika bisnis nyata — pengurutan, pemfilteran, agregasi — hanya tanpa efek eksternal. Basis data in-memory alih-alih Room atau HashMap alih-alih SharedPreferences — contoh klasik. Selengkapnya di klasifikasi test doubles Martin Fowler.

Poin Utama

  • Fake — implementasi kerja yang disederhanakan dengan logika nyata, tetapi tanpa dependensi eksternal
  • Penyimpanan In-memory — repositori fake menyimpan data di HashMap, bukan di basis data
  • Perbedaan dari Stub — stub mengembalikan data tetap, fake berisi logika yang dapat dijalankan
  • Android — InMemoryUserRepository sebagai Fake untuk menguji ViewModel dan UseCase
  • iOS — FakeNetworkSession dengan URLProtocol dan data uji alih-alih server nyata

Apa itu Fake dan mengapa diperlukan dalam pengujian?

Fake — implementasi antarmuka yang lengkap tetapi ringan, cocok untuk pengujian. Istilah ini diperkenalkan oleh Gerard Meszaros (2007) dalam buku «xUnit Test Patterns». Berbeda dengan stub yang mengembalikan jawaban tetap, fake berisi kode yang dapat dijalankan: dapat mengurutkan daftar, memfilter berdasarkan kondisi, menghitung jumlah catatan. Satu-satunya perbedaan dari implementasi produksi — fake bekerja dengan data in-memory dan tidak melakukan operasi I/O nyata.

Keuntungan utama — kecepatan. Pengujian dengan fake dijalankan dalam hitungan milidetik, karena tidak ada akses ke disk, jaringan, atau basis data. HashMap in-memory bekerja 100-1000 kali lebih cepat daripada Room atau CoreData. Pada saat yang sama, fake memeriksa logika bisnis nyata: pengurutan, pemfilteran, agregasi — semua yang tidak dapat diperiksa oleh stub, karena stub hanya mengembalikan apa yang diperintahkan. Fake memberikan keyakinan bahwa kode memproses data dengan benar, bukan hanya menerima jawaban yang telah ditentukan.

Kapan Fake lebih baik daripada Stub

Fake lebih baik daripada Stub — jika komponen yang diuji melakukan beberapa operasi pada data (mengambil, memfilter, mengurutkan, menyimpan), stub akan memerlukan konfigurasi setiap panggilan secara terpisah. Fake berisi logika di dalamnya — pengujian cukup memanggil metode dan memeriksa hasilnya. Di IT Sectr kami menggunakan fake untuk semua repositori dalam pengujian unit: repositori fake dengan HashMap mencakup 90% skenario tanpa konfigurasi Mockito atau MockK.

Fake vs Stub vs Mock: kapan memilih apa

Kriteria pemilihan — tentukan apa yang diperiksa pengujian: status atau interaksi. Jika pengujian memeriksa status (hasil kerja) dan menggunakan logika — diperlukan fake. Jika pengujian hanya membutuhkan data masukan tanpa logika — stub sudah cukup. Jika pengujian memeriksa fakta pemanggilan metode — diperlukan mock. Mencampur jenis test doubles dalam satu pengujian mempersulit pemahaman dan meningkatkan kerapuhan.

KriteriaFakeStubMock
Memiliki logikaYa (disederhanakan)TidakTidak
KecepatanTinggiMaksimalTinggi
Pemeriksaan perilakuTidak langsungTidakYa (verify)
PemeliharaanSatu kelas per antarmukaKonfigurasi per pengujianKonfigurasi per pengujian
RealismeTinggi (kode berfungsi)Rendah (data tetap)Sedang
Risiko positif palsuRendahSedangTinggi (pengujian rapuh)

Anti-pola: Fake yang bukan fake — kesalahan umum ketika pengembang menyebut objek fake yang sebenarnya adalah stub atau mock. Jika InMemoryUserRepository Anda tidak berisi logika (pemfilteran, pengurutan) — ini bukan fake, melainkan stub dengan penyimpanan in-memory. Fake berbeda dari stub justru karena memiliki logika yang dapat dijalankan. Jika repositori fake hanya mengembalikan apa yang dimasukkan ke dalamnya dan tidak memproses data — gunakan mock atau stub.

Aturan praktis memilih test double

Rekomendasi praktis — mulailah dengan fake untuk setiap repositori atau layanan. Jika fake lebih kompleks dari 50 baris — bagi menjadi beberapa kelas. Jika fake sama sekali tidak diperlukan (pengujian hanya memeriksa satu skenario dengan data tetap) — gunakan stub. Jika pengujian memeriksa apakah metode dipanggil dengan parameter tertentu — gunakan mock. Jangan optimalkan pilihan sebelumnya: tulis fake, dan jika ternyata berlebihan, ganti dengan stub dalam pengujian tertentu.

Membuat Objek Fake di Android untuk Room dan Retrofit

Repositori Fake untuk Room — contoh tipikal fake di Android. Implementasi produksi UserRepository menggunakan Room DAO dengan kueri SQLite. Versi fake menyimpan data di MutableList atau HashMap dan mengimplementasikan metode yang sama: getUser(id), saveUser(user), deleteUser(id). Fake berisi logika pencarian, pemfilteran, dan pengurutan — sama seperti repositori produksi, tetapi tanpa SQL. Ini memungkinkan pengujian ViewModel dan UseCase tanpa konfigurasi basis data Room.

kotlin
class FakeUserRepository : UserRepository {

    private val users = mutableListOf<User>()

    override suspend fun getUser(id: String): User? {
        return users.find { it.id == id }
    }

    override suspend fun saveUser(user: User) {
        val index = users.indexOfFirst { it.id == user.id }
        if (index >= 0) users[index] = user
        else users.add(user)
    }

    override suspend fun search(query: String): List<User> {
        return users.filter {
            it.name.contains(query, ignoreCase = true)
        }
    }
}

Fake untuk Retrofit API — alih-alih MockWebServer (yang merupakan stub, bukan fake) dapat dibuat implementasi ApiService yang mengembalikan data dari koleksi in-memory. Perbedaan: MockWebServer mencegat HTTP dan mengembalikan JSON, sedangkan fake-ApiService bekerja di tingkat antarmuka Kotlin tanpa serialisasi. Fake lebih cepat (tanpa parsing JSON) dan lebih sederhana untuk di-debug (bekerja dalam proses yang sama, bertipe). Cocok untuk pengujian di mana semantik HTTP (kode status, header) tidak penting.

FakeSharedPreferences untuk pengujian cepat

— skenario umum lainnya. SharedPreferences produksi menulis ke disk melalui commit/apply. Versi fake menyimpan pasangan kunci-nilai di HashMap dan langsung mengembalikan data. Mendukung metode yang sama: getString, putString, getInt, putInt, clear. Untuk Jetpack DataStore analognya adalah FakeDataStore dengan penyimpanan in-memory. Fake semacam itu mempercepat pengujian puluhan kali lipat, karena tidak ada operasi penulisan disk.

Implementasi Fake di iOS dengan penyimpanan in-memory

Fake di Swift — dibangun melalui protokol. Kelas produksi mengimplementasikan protokol dengan logika nyata (CoreData, URLSession). Struktur fake mengimplementasikan protokol yang sama dengan penyimpanan in-memory dan logika yang disederhanakan. Swift adalah bahasa dengan semantik nilai, sehingga struktur fake bersifat immutable dan aman dalam pengujian multi-thread. Ini memberikan keunggulan dibandingkan analog Android: akses ke data in-memory tidak perlu disinkronkan.

swift
protocol UserRepositoryProtocol {
    func getUser(id: String) async -> User?
    func saveUser(user: User) async
}

final class FakeUserRepository: UserRepositoryProtocol {
    private var storage: [String: User] = [:]

    func getUser(id: String) async -> User? {
        return storage[id]
    }

    func saveUser(user: User) async {
        storage[user.id] = user
    }
}

final class UserViewModelTests: XCTestCase {
    func test_save_and_load() async {
        let fake = FakeUserRepository()
        let vm = UserViewModel(repository: fake)
        let user = User(id: "1", name: "Alice")

        await vm.saveUser(user)
        let loaded = await vm.getUser(id: "1")

        XCTAssertEqual(loaded?.name, "Alice")
    }
}

Fake untuk CoreData — dalam proyek iOS dapat dibuat NSPersistentContainer in-memory dengan mengatur description.type = NSInMemoryStoreType. Ini adalah stack CoreData lengkap yang bekerja di memori. Fake semacam itu memungkinkan pengujian NSFetchRequest, predikat, dan pengurutan tanpa membuat file SQLite. Kecepatan: pengujian pada CoreData in-memory dijalankan 5-10 kali lebih cepat daripada analog disk. Kekurangan: NSManagedObjectModel harus dikonfigurasi setiap kali.

FakeURLProtocol — subclass dari URLProtocol untuk mencegat permintaan jaringan di iOS. Didaftarkan melalui URLProtocol.registerClass(fakeProtocol). Di dalamnya berisi kamus in-memory URL -> Data dan mengembalikan data tanpa permintaan nyata. Perbedaan dari stub: FakeURLProtocol dapat memeriksa isi permintaan, header, dan mengembalikan respons berbeda tergantung pada data masukan. Ini adalah fake karena berisi logika perutean permintaan.

Pola Penggunaan Fake dalam Proyek Seluler

Fake sebagai Test Fixture — pindahkan kelas fake ke modul pengujian bersama (androidTest/sharedTest atau TestSupport). Semua pengujian dalam proyek menggunakan InMemoryUserRepository yang sama. Ini menghilangkan duplikasi konfigurasi objek mock di setiap pengujian dan menjamin perilaku yang seragam. Perubahan logika fake memperbarui semua pengujian secara bersamaan. Di IT Sectr kami menyimpan kelas fake di sharedTest/java/com/itSectr/fake/ dan menghubungkannya melalui implementation project(:sharedTest).

Fake dengan data yang telah ditentukan — seringkali pengujian membutuhkan repositori yang sudah berisi beberapa catatan. Solusi: metode pabrik fakeWithData(vararg items) atau metode bawaan addDefaultData(). Pabrik membuat fake, mengisinya dengan data tipikal, dan mengembalikan objek siap pakai. Ini mengurangi boilerplate dalam pengujian: alih-alih mengonfigurasi panggilan mock, pengujian cukup memanggil FakeUserRepository.withUsers(alice, bob).

Fake dengan penghitungan panggilan — terkadang perlu memeriksa tidak hanya status, tetapi juga jumlah panggilan. Fake dapat berisi penghitung: saveCallCount, getUserCallCount. Pengujian memeriksa penghitung setelah eksekusi. Ini adalah kompromi antara fake murni (pemeriksaan status) dan mock (pemeriksaan interaksi). Penghitung tidak memeriksa argumen dan urutan panggilan — hanya jumlahnya. Untuk pemeriksaan argumen gunakan mock.

Fake dengan Callback — untuk menguji skenario asinkron, fake dapat menerima callback pada setiap panggilan: beforeGetUser, afterSaveUser. Ini memungkinkan simulasi penundaan, kesalahan, atau pemeriksaan status antara. Pendekatan seperti ini berguna untuk menguji status pemuatan UI: fake berhenti selama 100 ms, dan pengujian memeriksa apakah layar menampilkan pemuat. Dalam produksi callback tidak ada — ini murni fungsionalitas pengujian.

Pertanyaan Umum

Apa perbedaan Fake dengan Stub?

Fake berisi logika kerja — memfilter, mengurutkan, menghitung. Stub hanya mengembalikan jawaban yang telah ditentukan tanpa logika. Jika objek memiliki percabangan (if/else, when) — ini fake. Jika hanya berisi return values — ini stub. Fake lebih mahal dalam pemeliharaan, tetapi memberikan pengujian yang lebih realistis.

Kapan fake bisa berbahaya?

Ketika logika fake tidak sesuai dengan logika produksi. Misalnya, FakeUserRepository menggunakan pencarian case-sensitive, sedangkan produksi menggunakan case-insensitive. Pengujian lolos, tetapi pada kenyataannya ada bug. Solusi: uji logika fake secara terpisah atau gunakan fake hanya untuk antarmuka dengan logika sederhana (operasi CRUD). Untuk logika kompleks, tulis pengujian integrasi dengan basis data nyata.

Apakah Fake sama dengan in-memory database?

In-memory database — salah satu varian fake. Room.inMemoryDatabaseBuilder() membuat SQLite in-memory yang berperilaku seperti basis data produksi. Ini adalah fake yang sebenarnya. Tetapi fake juga bisa berada di tingkat repositori (tanpa SQL) dan di tingkat jaringan (FakeApiService). Basis data in-memory adalah kasus khusus fake di mana logika sedekat mungkin dengan yang asli.

Bisakah Fake dan Mock digabungkan dalam satu pengujian?

Ya, tetapi dengan hati-hati. Fake untuk repositori (data), Mock untuk AnalyticsTracker (verifikasi peristiwa). Pemisahan berdasarkan lapisan: fake untuk lapisan data, mock untuk lapisan analitik/pencatatan. Jangan membuat satu objek sekaligus fake dan mock — ini melanggar Prinsip Tanggung Jawab Tunggal dan membingungkan pengujian.

Bagaimana cara menguji Fake itu sendiri?

Uji fake dengan pengujian yang sama dengan implementasi produksi. Jika Anda memiliki UserRepositoryTest yang memeriksa save, get, delete — jalankan dua kali: dengan FakeUserRepository dan dengan RealUserRepository. Ini menjamin bahwa fake mengulangi perilaku kelas produksi. Jika fake mulai berperilaku berbeda — pengujian akan gagal pada kedua implementasi.

Kesimpulan

  • Fake — implementasi dependensi kerja yang disederhanakan dengan logika bisnis nyata dan penyimpanan in-memory
  • Perbedaan dari Stub — fake berisi logika (pemfilteran, pengurutan), stub hanya mengembalikan data
  • Kecepatan — fake bekerja 100-1000 kali lebih cepat daripada implementasi produksi tanpa operasi I/O
  • Android — InMemoryUserRepository, FakeDataStore, in-memory Room melalui Room.inMemoryDatabaseBuilder
  • iOS — fake berbasis protokol, CoreData in-memory, FakeURLProtocol untuk pencegatan HTTP
  • Praktik terbaik — pindahkan fake ke modul pengujian bersama dan gunakan di semua pengujian proyek
  • Uji fake — jalankan pengujian yang sama pada fake dan implementasi produksi untuk memeriksa konsistensi

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