Stub: mi ez, típusai és alkalmazása a tesztelésben

Szerző: IT Sectr Megjelenés: 2026-04-10 Olvasási idő: 9 perc

Stub (helyettesítő, tesztsegéd) — egy tesztobjektum, amely előre meghatározott válaszokat ad vissza metódushívásokra a valódi implementáció helyett. Mobilfejlesztésben a stubok elkülönítik a tesztelt modult a hálózati kérésektől, adatbázistól és fájlrendszertől, lehetővé téve a logika ellenőrzését a környezet beállítása nélkül. A mock-tól eltérően a stub nem ellenőrzi a viselkedést — csak adatokat szolgáltat. Bővebben Martin Fowler test doubles-ról szóló cikkében.

Főbb pontok

  • Stub — helyettesítő, amely adott értékeket ad vissza metódushívásokra logika nélkül
  • Elkülönítés — a stubok kikapcsolják a valódi függőségeket: API, adatbázis, fájlok, érzékelők
  • Különbség a Mock-tól — a stub nem ellenőrzi a hívásokat, csak a választ helyettesíti
  • Android — MockWebServer (OkHttp) stubként HTTP-hez, MockK.constantAnswer Kotlinhoz
  • iOS — OCMock és Swift protokollok tesztimplementációkkal stubokként

Mi az a Stub és miben különbözik más test doubles-tól?

Stub — egy helyettesítő objektum, amely a tesztben helyettesíti a valódi függőséget és előre meghatározott értékeket ad vissza adott hívásokra. A kifejezést Gerard Meszaros (2007) vezette be a „xUnit Test Patterns" című könyvében. A stub a test doubles kategóriába tartozik — olyan objektumok, amelyek a tesztelés során helyettesítik a valódi komponenseket. A stub fő célja, hogy kiszámítható adatokkal lássa el a tesztelt blokkot, kiküszöbölve a külső rendszerek bizonytalanságát.

Működési elv — a teszt a végrehajtás előtt konfigurálja a stubot: „amikor a getUsers() metódus meghívásra kerül, add vissza ezt a felhasználói listát". A stub nem tartalmaz üzleti logikát, nem ellenőrzi a hívások sorrendjét, és nem rögzíti a hozzáférési előzményeket. Egyszerűen a valódi komponens helyén áll, és azt adja vissza, amit mondtak neki. Az Android tesztelés kontextusában ez azt jelenti, hogy az OkHttp kliens nem küld valódi kérést a szervernek, hanem a MockWebServer-től kap választ, amely stubként van konfigurálva.

  • Stub — adatokat ad vissza, nem ellenőrzi a hívásokat
  • Mock — adatokat ad vissza és ellenőrzi a viselkedést (verify)
  • Fake — működő egyszerűsített implementáció valódi logikával
  • Spy — beburkolja a valódi objektumot, rögzítve a hívásokat
  • Dummy — átadásra kerül, de nem használatos (null, üres objektum)

Mikor használd — a stubok optimálisak az UI réteg (ViewModel, Presenter) és az üzleti logika (UseCase, Interactor) teszteléséhez, ahol ellenőrizni kell a reakciót adott adatokra: üres lista, a szerver 500-as hibát adott vissza, lejárt token. Minden olyan eset, ahol a teszt meghatározott bemeneti állapotot igényel, a stub feladata. Minden tesztforgatókönyvhöz saját stub konfiguráció készül, ami olvashatóvá és kiszámíthatóvá teszi a teszteket.

A test doubles osztályozása Meszaros szerint

Gerard Meszaros (2007) a „xUnit Test Patterns" című könyvében ötféle test double-t azonosított: dummy, stub, spy, mock, fake. Minden típus a saját feladatát oldja meg. Dummy — átadásra kerül, de nem használatos. Stub — adatokat ad vissza. Spy — rögzíti a hívásokat. Mock — ellenőrzi a viselkedést. Fake — egyszerűsített logikát tartalmaz. Ennek az osztályozásnak a megértése segít a fejlesztőnek kiválasztani a megfelelő eszközt minden tesztforgatókönyvhöz.

Hol használnak stubokat a mobilalkalmazások tesztelésében

Stubok hálózati kérésekhez

Hálózati kérések — a stubok leggyakoribb alkalmazási forgatókönyve. Az alkalmazás HTTP-hívásokat küld az API-nak, és a tesztben ellenőrizni kell a reakciót különböző válaszokra: sikeres JSON, 401-es hiba (jogtalan), időtúllépés, üres tömb. A MockWebServer (OkHttp) Androidon és az URLProtocol (iOS) stubként működik, előre meghatározott HTTP-válaszokat adva vissza valódi szerverkapcsolat nélkül. Ez másodpercekről ezredmásodpercekre gyorsítja a teszteket.

Adatbázis — a Room (Android) és a CoreData (iOS) rendelkezik in-memory változatokkal, de ezek beállítása még mindig időt vesz igénybe. A stub a repository helyett előre elkészített Entity listákat ad vissza anélkül, hogy hozzányúlna az adatbázishoz. Ez különösen hatékony a ViewModel teszteléséhez, ahol a rendezést, szűrést vagy adatátalakítást kell ellenőrizni. A teszt ezredmásodpercek alatt fut le, függetlenül az adatok mennyiségétől.

Rendszerszolgáltatások — a LocationManager, SensorManager, SharedPreferences valódi eszközt vagy emulátort igényel. A LocationProvider stubja adott koordinátákat, a SensorManageré rögzített gyorsulásmérő értékeket ad vissza. iOS-en az analóg a CLLocationManager tesztimplementációval rendelkező delegáttal. Stubok nélkül az ilyen tesztek fizikai eszközt igényelnek meghatározott körülményekkel.

Fájlrendszer és gyorsítótár — képek betöltése, válaszok gyorsítótárazása, konfigurációs fájlokkal való munka — ezek a műveletek a lemez állapotától függenek. A FileManager vagy ImageCache stubja valódi fájlok olvasása nélkül ad vissza sikert/hibát. Ez kiküszöböli a tesztek hamis meghiúsulását az eltérő elérési utak vagy jogosultságok miatt a különböző fejlesztői gépeken.

Stub vs Mock vs Fake: legfontosabb különbségek

Felelősségi körök megosztása — háromféle test double különböző feladatokat old meg. Stub: „adj nekem adatokat". Mock: „ellenőrizd, hogy hívtak-e". Fake: „úgy működöm, mint az igazi, csak egyszerűbben". A különbség kritikus a tesztek olvashatósága szempontjából: ha egy teszt mock-ot használ ott, ahol stub kellene, túlterhelődik a tesztelt forgatókönyvhöz nem kapcsolódó verify hívásokkal.

JellemzőStubMockFake
CélAdatok szolgáltatásaInterakció ellenőrzéseEgyszerűsített implementáció
LogikaNincsNincsVan (de egyszerűsített)
EllenőrzésNincsVan (verify)Közvetett (állapoton keresztül)
RugalmasságAlacsony — fix válaszokKözepesMagas — logika alkalmazkodik
SebességMaximálisMagasKözepes
PéldaMockWebServer JSON-t ad visszaMockito.verify(repository).save()InMemoryRepository HashMap-mel

Gyakorlati szabály — ha a teszt azt ellenőrzi, milyen adatokat kapott a tesztelt komponens — használj stubot. Ha a teszt azt ellenőrzi, hogy a komponens meghívta-e a függőség metódusát a megfelelő argumentumokkal — használj mock-ot. Ha egyszerűen le akarod cserélni az adatbázist egy hash táblára — ez fake. A típusok keverése egy tesztben törékennyé teszi azt: implementációváltáskor mind a stubot, mind a verify logikát át kell írni.

Antiminta: Stub verify-al

Stub verify-al — gyakori hiba, amikor a fejlesztő konfigurálja a stubot, majd hozzáadja a verify(stub).method()-et. A stub definíció szerint nem ellenőrizendő — az ellenőrzéshez mock van. Ha ellenőrizni kell, hogy a metódust meghatározott argumentumokkal hívták-e, használj Mockito.mock()-ot a Mockito.stub() helyett. Ez a szétválasztás világosan tartja a teszt szándékát más fejlesztők számára.

Stubok implementálása Androidon MockWebServer és MockK segítségével

MockWebServer — OkHttp könyvtár HTTP stubok létrehozásához Androidon és JVM-en. Egy helyi HTTP szervert indít a megadott porton, amely elfogja az OkHttp kliens kéréseit és előre meghatározott válaszokat ad vissza. A beállítás három sorból áll: szerver létrehozása, válasz sorba állítása (enqueue), indítás. A teszt egymás után több választ is sorba állíthat lapozási vagy újrapróbálkozási forgatókönyvekhez.

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 — alternatíva a Mockito-hoz Kotlinhoz, first-class támogatással a korutinokhoz, kiterjesztési függvényekhez és sealed osztályokhoz. A stubok MockK-ban a coEvery (suspend függvényekhez) és az every (szokásos függvényekhez) segítségével hozhatók létre. A MockWebServer-től eltérően a MockK egyedi függőségi metódusokat helyettesít, nem a teljes HTTP réteget. Ez kényelmes a UseCase vagy Interactor egységtesztjeihez, ahol a függőségek repository absztrakciók.

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 — integrációs tesztekhez használj MockWebServer-t (elfogja a valódi HTTP-t), egységtesztekhez — MockK-t (helyettesíti az interfészeket). Ne helyettesítsd azt, amit nem tesztelsz: ha a teszt a Repository-t ellenőrzi, ne helyettesítsd benne az OkHttp klienst — használj valódi MockWebServer-t a HTTP szinten. Ez a szabály relevánsan tartja a teszteket és csökkenti a törékenységet refaktoráláskor.

Stubok implementálása iOS-en OCMock és protokollok segítségével

Swift protokollok stubokként — az iOS natív megközelítésben a stub a függőségi protokollnak megfelelő tesztstruktúra behelyettesítésével valósul meg. A valódi NetworkService helyett a teszt StubNetworkService-t kap, amely rögzített adatokat ad vissza. A Swift statikus típusú nyelv, ezért a stub-nak ugyanannak a protokollnak kell megfelelnie, mint a valódi szolgáltatásnak. A fordító garantálja, hogy a stub implementálja az összes szükséges metódust.

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 Objective-C-hez — könyvtár stubok és mockok létrehozásához örökölt iOS projektekben. Az OCMock támogatja a stub metódusokat argumentumokkal és visszatérési értékekkel. A modern Swift projektek a protokoll-alapú megközelítést részesítik előnyben kézi stubokkal — ez minden metódus felett kontrollt ad, és nem igényel külső függőségeket. Az OCMock opció marad azon projektek számára, ahol az összes függőség protokollosítása gazdaságilag nem indokolt.

URLProtocol HTTP stubokhoz — iOS rendszermechanizmus hálózati kérések elfogására URLProtocol alosztályon keresztül. A teszt regisztrál egy egyéni URLProtocol-ot, amely elfogja az URLSession-t és stub válaszokat ad vissza. Előny a kézi stubokkal szemben: nem kell megváltoztatni az alkalmazás architektúráját — az URLSession valódi marad, de az adatok protokoll szinten cserélődnek. Hátrány: nehezebb debugolni, mint egy explicit stub szolgáltatást.

Gyakran Ismételt Kérdések

Miben különbözik a Stub a Mock-tól?

Stub előre meghatározott adatokat ad vissza, és nem ellenőrzi a hívás tényét. A Mock emellett ellenőrzi (verify), hogy a metódust a megfelelő argumentumokkal hívták-e. A Stub a „mit adjak vissza" kérdésre válaszol, a Mock — a „volt-e hívás" kérdésre. Használj stubot állapotellenőrzéshez, mock-ot interakcióellenőrzéshez.

Mikor használjak Fake-et Stub helyett?

Fake akkor kell, amikor a teszt működő (bár egyszerűsített) implementációt igényel — például in-memory adatbázist Room helyett. A Stub egyedi forgatókönyvekhez alkalmas előre meghatározott adatokkal. Ha ugyanazt a stubot ismételgeted 10 tesztben — valószínűleg Fake-re van szükséged. A Fake csökkenti az ismétlést, mert a logika egy osztályban él.

Lehet-e statikus metódusokat stublolni?

Androidon — MockK Kotlin objektumok (object) esetén támogatja a mockkObject()-et, beleértve a Java osztályok statikus metódusait a mockkStatic()-en keresztül. iOS-en — a Swift statikus metódusai nem stublolhatók közvetlenül; használj protokollokat és DI-t, hogy a static hívást a protokoll példánymetódusával helyettesítsd. A statikus stubok technikai adósságok, kerülendők az új kódban.

Hogyan stubloljak hálózati kéréseket Androidon?

Használj MockWebServer-t (OkHttp) — ez egy helyi HTTP szerverként működik, amely sorba állítja (enqueue) a válaszokat. Retrofit esetén elég a base URL-t localhost:8080-ra cserélni. Ktor esetén használj MockEngine-t — a HttpStatement helyettesítésének beépített mechanizmusát. Mindkét megközelítés valódi internet nélkül működik, és teljes kontrollt ad a válasz státuszkódja, törzse és fejléce felett.

Stub vs Spy — mi a különbség?

Spy beburkolja a valódi objektumot és rögzíti a hívásokat, míg a Stub teljesen lecseréli az objektumot fix válaszokra. A Spy lehetővé teszi a valódi implementáció részleges használatát (a többi metódus úgy működik, mint korábban), a stub pedig nem. Ha ellenőrizni kell, hogy egy metódust meghívtak, de a logika egy részének végre kell hajtódnia — használj spy-t, ne stubot.

Összefoglalás

  • Stub — helyettesítő objektum, amely előre meghatározott válaszokat ad vissza metódushívásokra a tesztelés során
  • Függőségek elkülönítése — a stubok helyettesítik a hálózati kéréseket, adatbázisokat, rendszerszolgáltatásokat és fájlrendszert
  • Különbség a Mock-tól — a stub nem ellenőrzi a hívásokat, csak adatokat ad vissza viselkedésvizsgálat nélkül
  • Android eszközök — MockWebServer HTTP-hez, MockK Kotlin interfészekhez korutin támogatással
  • iOS eszközök — protokoll-alapú stubok Swift-ben, URLProtocol HTTP-hez, OCMock Objective-C-hez
  • Ne keverd a szerepeket — ne adj hozzá verify-t a stubhoz, használj mock-ot a hívások ellenőrzéséhez
  • Stub + MockWebServer — szabványos megközelítés integrációs tesztekhez valódi szerver nélkül

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is