Test Doubles — ce este, tipuri și aplicare

Autor: IT Sectr Publicat: 2026-04-10 Timp de citire: 9 min

Test Doubles — sunt obiecte de înlocuire utilizate în testele unitare în locul dependențelor reale. Termenul a fost introdus de Gerard Meszaros în cartea „xUnit Test Patterns“ (2007) ca un concept general pentru Mock, Stub, Fake, Spy și Dummy. Potrivit Martin Fowler (2024), Test Doubles permit izolarea componentului testat de mediul său, făcând testele deterministe, rapide și independente de serviciile externe.

Principalele

  • Test Doubles — termen general pentru toate tipurile de obiecte de înlocuire în testare
  • Mock verifică interacțiunea: ce metode au fost apelate și cu ce argumente
  • Stub returnează valori prestabilite fără a verifica apelurile
  • Fake — o implementare simplificată funcțională (de exemplu, bază de date in-memory)
  • Spy înregistrează apelurile pentru verificare ulterioară, Dummy completează parametrii

Ce sunt Test Doubles?

Test Doubles — este un termen din industria auto (cascador, „dublură“ pentru actori), transferat în dezvoltarea de software. Așa cum un cascador înlocuiește un actor într-o scenă periculoasă, Test Double înlocuiește un component real într-un scenariu de test. Acest lucru este necesar când dependența reală este indisponibilă, lentă, non-deterministă sau are efecte secundare.

Conceptul de Test Double include cinci tipuri specifice, fiecare rezolvând propria sarcină. Tipologia lui Meszaros este canonică și utilizată în toate ghidurile moderne de testare. Diferența între tipuri constă în gradul de control și verificare: de la simpla completare a parametrilor (Dummy) până la verificarea completă a secvenței de apeluri (Mock).

De ce sunt necesare Test Doubles

Scopul principal al Test Doubles este izolarea modulului testat. În dezvoltarea mobilă, dependențele reale sunt serverele API, bazele de date, sistemul de fișiere, senzorii dispozitivului, serviciile de sistem (LocationManager, Camera, Bluetooth). Utilizarea directă a acestor componente face testele lente, fragile și dependente de mediu. Potrivit Google Testing Blog (2023), testele unitare bine izolate se execută în milisecunde, iar cele de integrare — în secunde și minute.

Cinci tipuri de Test Doubles

Clasificarea Gerard Meszaros include cinci tipuri de Test Doubles, care diferă prin comportament și scopul utilizării. Înțelegerea diferențelor dintre ele stă la baza testării unitare corecte.

Dummy

Dummy — este un obiect transmis metodei testate, dar care nu este niciodată utilizat. Dummy este necesar doar pentru a satisface semnătura metodei. În Kotlin, acesta este adesea null, emptyList() sau un obiect cu înlocuitori. Dummy nu trebuie să conțină nicio logică — dacă este apelat, testul trebuie să eșueze.

Fake

Fake — este o implementare simplificată, dar funcțională a unei interfețe. Spre deosebire de Mock și Stub, Fake conține logică de afaceri reală, dar într-o formă simplificată. Exemplul clasic — InMemoryUserRepository, care stochează date în HashMap în locul unei baze de date. Fake este utilizat când trebuie testată logica dependentă de stare, dar fără costurile infrastructurii reale.

TipScopExemplu
DummyCompletarea parametruluinull, obiect gol
FakeImplementare simplificată funcționalăInMemoryRepository
StubReturnarea unei valori fixewhen(api.getUser()).thenReturn(user)
SpyÎnregistrarea apelurilor pentru verificareverify(spy).save(user)
MockVerificarea interacțiuniiverify(mock).sendEmail(email)

Stub

Stub returnează valori prestabilite pentru anumite apeluri. Stub nu verifică dacă a fost apelat — pur și simplu furnizează date. În Mockito, Stub se creează prin when(method).thenReturn(value). Stub este ideal pentru testare când dependența trebuie să returneze o valoare specifică, dar simplul fapt al apelului nu este important.

Spy

Spy — este un înveliș în jurul unui obiect real care înregistrează toate apelurile pentru verificare ulterioară. Spre deosebire de Mock, Spy delegă apelurile către obiectul real, dar permite verificarea faptului că acestea au avut loc. În Mockito, Spy se creează prin spy(realObject). Spy este util pentru mocking parțial, când se dorește utilizarea unui obiect real, dar verificarea unor apeluri.

Mock

Mock — este un obiect cu așteptări de apeluri predefinite. Mock verifică dacă anumite metode au fost apelate cu anumite argumente și într-o anumită ordine. Spre deosebire de Stub, Mock se concentrează pe verificarea comportamentului, nu pe returnarea datelor. Mock este cel mai puternic și cel mai frecvent utilizat tip de Test Double în dezvoltarea mobilă.

Mock și Stub: diferențe cheie

Diferența dintre Mock și Stub cauzează adesea confuzie chiar și printre dezvoltatorii experimentați. Diferența principală constă în scop: Stub verifică starea (state verification), Mock verifică comportamentul (behavior verification).

Stub răspunde la întrebarea: „codul a returnat rezultatul corect?“. Mock răspunde la întrebarea: „codul a apelat metodele corecte cu argumentele corecte?“. În dezvoltarea mobilă, Stub este utilizat când rezultatul este important (de exemplu, datele din repository), iar Mock — când efectele secundare sunt importante (de exemplu, trimiterea e-mailului, scrierea în baza de date).

kotlin
// Stub: verificarea stării
every { repository.getUsers() } returns listOf(user)
val result = useCase.getUsers()
assertEquals(1, result.size)

// Mock: verificarea comportamentului
every { analytics.logEvent("purchase") } returns Unit
useCase.purchase(item)
verify { analytics.logEvent("purchase") }

Exemple de Test Doubles în Kotlin

Exemple practice ale tuturor celor cinci tipuri de Test Doubles în Kotlin utilizând MockK — cea mai populară bibliotecă de mocking pentru proiecte Android.

Fake: InMemoryUserRepository

kotlin
class InMemoryUserRepository : UserRepository {
    private val store = mutableMapOf<String, User>()

    override fun save(user: User) {
        store[user.email] = user
    }

    override fun findByEmail(email: String): User? {
        return store[email]
    }
}

Stub + Mock: test UseCase

kotlin
class RegisterUseCaseTest {
    private val api = mockk<AuthApi>()
    private val repo = spyk(InMemoryUserRepository())
    private val useCase = RegisterUseCase(api, repo)

    fun `register user successfully`() = runTest {
        // Stub: returnăm un răspuns API fix
        coEvery { api.register("test@test.com") } returns AuthResult.Success("token123")

        val result = useCase.execute("test@test.com")

        // Verify: verificăm că utilizatorul a fost salvat
        verify { repo.save(any()) }
        assertTrue(result.isSuccess())
    }
}

Dummy: test cu parametru neutilizat

kotlin
data class Logger(val appContext: Context, val format: FormatType)

fun `test logger with dummy context`() {
    // Dummy: Context nu este utilizat în interiorul Logger
    val dummyContext = mockk<Context>()
    val logger = Logger(dummyContext, FormatType.JSON)
    assertEquals(FormatType.JSON, logger.format)
}

Când să utilizați fiecare tip în dezvoltarea mobilă

Alegerea tipului de Test Double depinde de ceea ce se testează exact: starea, comportamentul sau integrarea. În dezvoltarea mobilă pe Android și iOS s-au format următoarele recomandări.

Pentru ViewModel și UseCase

La testarea ViewModel-ului, utilizați Mock pentru dependențele care produc efecte secundare (repository-uri, analitică, navigare) și Stub pentru dependențele care returnează date (clienți API, ContentProvider). Aceasta permite verificarea faptului că ViewModel gestionează corect atât scenariile de succes, cât și pe cele de eroare.

Pentru Repository și Stratul de Date

La nivelul Repository, sunt preferate Fake (implementări de bază de date in-memory) și Stub (răspunsuri API fixe). Fake permite verificarea logicii de cache și a modului offline fără configurarea SQLite. Stub simulează diverse coduri HTTP: 200, 404, 500, timeout.

  • Teste unitare ale logicii de afaceri — Mock pentru toate dependențele externe, Dummy pentru parametrii neutilizați
  • Teste de integrare — Fake în loc de Mock (verificăm că componentele funcționează împreună)
  • Teste UI — Stub pentru răspunsurile API (prin MockWebServer sau WireMock)
  • Teste de cache — Fake pentru baza de date (in-memory în loc de Room/SQLite)
  • Teste de asincronizare — Mock cu suport pentru corutine (MockK + Turbine pentru Flow)

Greșeli tipice la utilizarea înlocuitorilor

Utilizarea incorectă a Test Doubles — una dintre cele mai frecvente cauze ale testelor fragile care se strică la fiecare refactorizare.

Over-mocking: utilizarea excesivă a Mock

Cea mai frecventă greșeală — mock-area oricărui lucru. Dacă fiecare dependență într-un test este înlocuită cu Mock, testul încetează să verifice comportamentul real. Mock trebuie să fie doar pentru dependențe externe (rețea, bază de date, sistem de fișiere, servicii de sistem). Componentele interne ale aplicației (Value Object, data class, utilitare simple) nu trebuie înlocuite.

Under-specification: specificare insuficientă

A doua greșeală — crearea unui Mock fără definirea așteptărilor. Dacă o metodă este apelată fără every / when, Mock returnează o valoare implicită (null, 0, false). Aceasta poate duce la teste fals-pozitive atunci când Mock returnează în tăcere null, iar testul interpretează acest lucru ca un comportament corect.

Over-verification: verificare excesivă

A treia greșeală — verificarea fiecărui apel al fiecărui Mock. Verify trebuie utilizat doar pentru apelurile critice din punctul de vedere al logicii de afaceri. Verificarea excesivă face testele fragile: modificarea ordinii apelurilor în codul de producție strică testele fără a modifica comportamentul.

Întrebări frecvente

Care este diferența dintre Mock și Stub?

Stub returnează date și verifică starea (ce s-a returnat), iar Mock verifică comportamentul (ce metode au fost apelate). Stub = „return X“, Mock = „verifică că Y a fost apelat cu argumentul Z“. În testele reale, un singur obiect acționează adesea atât ca Stub, cât și ca Mock simultan.

Când să utilizați Fake în loc de Mock?

Fake este preferat în locul Mock-ului atunci când se testează logica dependentă de stare: cache, modul offline, tranzacții. Fake (implementarea in-memory) permite verificarea acestor scenarii fără apeluri fragile de verify. Mock este mai potrivit pentru verificarea trimiterii datelor: analitică, notificări push, e-mail.

Care bibliotecă de Test Doubles este mai bună pentru Android?

Pentru proiectele Android în Kotlin este recomandat MockK. Acesta suportă corutine, funcții suspend, sealed class și funcții extension fără configurare suplimentară. Pentru proiectele în Java, standardul rămâne Mockito — cea mai populară bibliotecă cu documentație extinsă.

Cum se testează Kotlin Flow cu Test Doubles?

Pentru testarea Kotlin Flow, utilizați biblioteca Turbine în combinație cu MockK. Turbine simplifică verificarea emisiei Flow: se poate verifica ordinea valorilor, finalizarea fluxului și excepțiile. Stub pentru Flow returnează flowOf(value), Mock verifică dacă Flow a fost colectat.

Este permisă utilizarea Test Doubles în testele UI?

Da, dar la nivelul răspunsurilor API, nu al componentelor UI. Bibliotecile MockWebServer (OkHttp) și WireMock permit înlocuirea răspunsurilor HTTP în testele UI. Componentele UI în sine (Compose, SwiftUI Views) nu trebuie înlocuite — comportamentul lor se testează prin teste de screenshot și Espresso.

Rezumat

  • Test Doubles — termen general pentru cinci tipuri de obiecte de înlocuire: Mock, Stub, Fake, Spy, Dummy
  • Mock verifică comportamentul (verify), Stub returnează date (thenReturn), Fake — funcționează ca o implementare reală simplificată
  • Spy învelește obiectul real și înregistrează apelurile, Dummy completează parametrii neutilizați
  • Tipologia Gerard Meszaros — clasificare canonică utilizată în toate framework-urile moderne de mocking
  • Pentru proiectele Kotlin este recomandat MockK, pentru Java — Mockito, pentru iOS — Cuckoo sau OHHTTPStubs
  • Greșeli tipice: over-mocking (înlocuirea oricărui lucru), under-specification (așteptări nedefinite), over-verification (verify excesiv)
  • Fake preferat în locul Mock la testarea logicii cu stare — cache, modul offline și tranzacții

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și