Fake — шта је то, намена и како користити у тестирању

Аутор: IT Sectr Објављено: 2026-04-10 Време читања: 9 мин

Fake (фејк) — радна упрошћена имплементација зависности која се понаша као прави компонент, али користи in-memory складиште или друге лаке механизме уместо продукционе инфраструктуре. За разлику од stub, fake садржи реалну пословну логику — сортирање, филтрирање, агрегацију — само без спољних ефеката. In-memory база података уместо Room или HashMap уместо SharedPreferences — класични примери. Више у класификацији test doubles Мартина Фаулера.

Главно

  • Fake — упрошћена радна имплементација са стварном логиком, али без спољних зависности
  • In-memory складиштење — fake-репозиторијум чува податке у HashMap, а не у бази
  • Разлика од Stub — stub враћа фиксне податке, fake садржи извршну логику
  • Android — InMemoryUserRepository као Fake за тестирање ViewModel и UseCase
  • iOS — FakeNetworkSession са URLProtocol и тест подацима уместо правог сервера

Шта је Fake и зашто је потребан у тестирању?

Fake — потпуна, али лагана имплементација интерфејса, погодна за тестирање. Термин је увео Gerard Meszaros (2007) у књизи «xUnit Test Patterns». За разлику од stub, који враћа строго задате одговоре, fake садржи извршни код: може да сортира листу, филтрира по услову, преброји записе. Једина разлика од продукционе имплементације — fake ради са in-memory подацима и не извршава реалне I/O операције.

Главна предност — брзина. Тестови са fake се извршавају у милисекундама, јер нема приступа диску, мрежи или бази података. In-memory HashMap ради 100-1000 пута брже од Room или CoreData. Истовремено fake проверава реалну пословну логику: сортирање, филтрирање, агрегацију — све то stub не може да провери, јер stub враћа само оно што му је речено. Fake даје сигурност да код исправно обрађује податке, а не само прима унапред одређени одговор.

Када је Fake бољи од Stub

Fake је бољи од Stub — ако тестирана компонента обавља више операција над подацима (извукао, филтрирао, сортирао, сачувао), stub ће захтевати подешавање сваког позива посебно. Fake садржи логику у себи — тест само позива методе и проверава резултат. У IT Sectr користимо fake за све репозиторијуме у unit тестовима: fake-репозиторијум са HashMap покрива 90% сценарија без подешавања Mockito или MockK.

Fake vs Stub vs Mock: када шта изабрати

Критеријум избора — одредите шта тест проверава: стање или интеракцију. Ако тест проверава стање (резултат рада) и користи логику — потребан је fake. Ако тесту требају само улазни подаци без логике — довољан је stub. Ако тест проверава чињеницу да је метод позван — потребан је mock. Мешање типова test doubles у једном тесту отежава разумевање и повећава крхкост.

КритеријумFakeStubMock
Присуство логикеДа (упрошћена)НеНе
БрзинаВисокаМаксималнаВисока
Провера понашањаИндиректнаНеДа (verify)
ОдржавањеЈедна класа по интерфејсуПодешавање за сваки тестПодешавање за сваки тест
РеализамВисок (код ради)Низак (фиксни подаци)Средњи
Ризик лажних алармаНизакСредњиВисок (крхки тестови)

Антиобразац: Fake који није fake — честа грешка када програмер назове fake објекат који је заправо stub или mock. Ако ваш InMemoryUserRepository не садржи логику (филтрирање, сортирање) — то није fake, већ stub са in-memory складиштењем. Fake се разликује од stub управо по присуству извршне логике. Ако fake-репозиторијум само враћа оно што је у њега стављено и не обрађује податке — користите mock или stub.

Практично правило избора test double

Практична препорука — почните са fake за сваки репозиторијум или сервис. Ако је fake сложенији од 50 линија — поделите на неколико класа. Ако fake уопште није потребан (тест проверава само један сценарио са фиксним подацима) — користите stub. Ако тест проверава да ли је метод позван са одређеним параметрима — користите mock. Не оптимизујте избор унапред: напишите fake, и ако се покаже сувишним, замените га stub у конкретном тесту.

Креирање Fake-објеката на Android-у за Room и Retrofit

Fake репозиторијум за Room — типичан пример fake на Android-у. Продукциона имплементација UserRepository користи Room DAO са SQLite упитима. Fake верзија чува податке у MutableList или HashMap и имплементира исте методе: getUser(id), saveUser(user), deleteUser(id). Fake садржи логику претраге, филтрирања и сортирања — исту као у продукционом репозиторијуму, али без SQL. Ово омогућава тестирање ViewModel и UseCase без подешавања 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 за Retrofit API — уместо MockWebServer (који је stub, а не fake) можете креирати имплементацију ApiService која враћа податке из in-memory колекције. Разлика: MockWebServer пресреће HTTP и враћа JSON, а fake-ApiService ради на нивоу Kotlin интерфејса без серијализације. Fake је бржи (нема парсирања JSON) и једноставнији за отклањање грешака (ради у истом процесу, типизиран). Погодан за тестове где HTTP семантика (статус кодови, заглавља) није важна.

FakeSharedPreferences за брзе тестове

— још један чест сценарио. Продукционе SharedPreferences пишу на диск преко commit/apply. Fake верзија чува парове кључ-вредност у HashMap и тренутно враћа податке. Подржава исте методе: getString, putString, getInt, putInt, clear. За Jetpack DataStore аналог — FakeDataStore са in-memory складиштем. Овакви fake убрзавају тестове десетинама пута, јер нема операција уписа на диск.

Fake имплементације на iOS-у са in-memory складиштима

Fake у Swift-у — гради се кроз протоколе. Продукциона класа имплементира протокол са реалном логиком (CoreData, URLSession). Fake структура имплементира исти протокол са in-memory складиштем и упрошћеном логиком. Swift је језик са вредносном семантиком, па су fake структуре имутабилне и безбедне у вишенитним тестовима. Ово даје предност над Android аналогијама: није потребно синхронизовати приступ in-memory подацима.

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 за CoreData — у iOS пројектима можете креирати in-memory NSPersistentContainer постављањем description.type = NSInMemoryStoreType. Ово је пуноправан CoreData стек који ради у меморији. Такав fake омогућава тестирање NSFetchRequest, предиката и сортирања без креирања SQLite фајла. Брзина: тестови на in-memory CoreData извршавају се 5-10 пута брже него на дисковном аналогу. Недостатак: потребно је подешавати NSManagedObjectModel сваки пут.

FakeURLProtocol — подкласа URLProtocol за пресретање мрежних захтева на iOS-у. Региструје се преко URLProtocol.registerClass(fakeProtocol). Унутар садржи in-memory речник URL -> Data и враћа податке без стварног захтева. Разлика од stub: FakeURLProtocol може проверити тело захтева, заглавља и вратити различите одговоре у зависности од улазних података. Ово је fake јер садржи логику рутирања захтева.

Обрасци употребе Fake у мобилним пројектима

Fake као Test Fixture — извуците fake класе у заједнички тест модул (androidTest/sharedTest или TestSupport). Сви тестови у пројекту користе исти InMemoryUserRepository. Ово елиминише дуплирање подешавања mock објеката у сваком тесту и гарантује једнообразно понашање. Промена логике fake ажурира све тестове истовремено. У IT Sectr чувамо fake класе у sharedTest/java/com/itSectr/fake/ и повезујемо преко implementation project(:sharedTest).

Fake са унапред постављеним подацима — често тестовима треба репозиторијум који већ садржи неке записе. Решење: фабрички метод fakeWithData(vararg items) или уграђени метод addDefaultData(). Фабрика креира fake, пуни га типичним подацима и враћа објекат спреман за употребу. Ово смањује boilerplate у тестовима: уместо подешавања mock позива, тест само позива FakeUserRepository.withUsers(alice, bob).

Fake са бројањем позива — понекад је потребно проверити не само стање, већ и број приступа. Fake може садржати бројаче: saveCallCount, getUserCallCount. Тест проверава бројач након извршења. Ово је компромис између чистог fake (провера стања) и mock (провера интеракције). Бројачи не проверавају аргументе и редослед позива — само број. За проверу аргумената користите mock.

Fake са Callback-ом — за тестирање асинхроних сценарија, fake може прихватити callback при сваком позиву: beforeGetUser, afterSaveUser. Ово омогућава симулацију кашњења, грешака или проверу међустања. Такав приступ је користан за тестирање стања учитавања UI: fake прави паузу од 100 ms, а тест проверава да ли екран приказује loader. У продукцији callback не постоји — то је чисто тестна функционалност.

Често постављана питања

Чиме се Fake разликује од Stub?

Fake садржи радну логику — филтрира, сортира, броји. Stub враћа само унапред задате одговоре без логике. Ако објекат има гранање (if/else, when) — то је fake. Ако садржи само return values — то је stub. Fake је скупљи за одржавање, али даје реалистичније тестове.

Када fake може бити штетан?

Када се fake логика не поклапа са продукционом логиком. На пример, FakeUserRepository користи case-sensitive претрагу, а продукција — case-insensitive. Тест пролази, а у стварности постоји грешка. Решење: тестирајте fake логику одвојено или користите fakes само за интерфејсе са једноставном логиком (CRUD операције). За сложену логику пишите интеграционе тестове са правом базом података.

Да ли је Fake исто што и in-memory database?

In-memory database — једна од варијанти fake. Room.inMemoryDatabaseBuilder() креира in-memory SQLite који се понаша као продукциона база. Ово је пуноправни fake. Али fake може бити и на нивоу репозиторијума (без SQL) и на нивоу мреже (FakeApiService). In-memory база података је посебан случај fake, када је логика максимално приближена стварној.

Може ли се комбиновати Fake и Mock у једном тесту?

Да, али опрезно. Fake за репозиторијум (подаци), Mock за AnalyticsTracker (верификација догађаја). Подела по слојевима: fake за слој података, mock за слој аналитике/логовања. Не правите један објекат истовремено fake и mock — то крши принцип јединствене одговорности и компликује тест.

Како тестирати сам Fake?

Тестирајте fake истим тестовима као и продукциону имплементацију. Ако имате UserRepositoryTest који проверава save, get, delete — покрените га два пута: са FakeUserRepository и са RealUserRepository. Ово гарантује да fake понавља понашање продукционе класе. Ако fake почне да се понаша другачије — тест ће пасти на обе имплементације.

Закључци

  • Fake — радна упрошћена имплементација зависности са реалном пословном логиком и in-memory складиштењем
  • Разлика од Stub — fake садржи логику (филтрирање, сортирање), stub само враћа податке
  • Брзина — fake ради 100-1000 пута брже од продукционе имплементације без I/O операција
  • Android — InMemoryUserRepository, FakeDataStore, in-memory Room преко Room.inMemoryDatabaseBuilder
  • iOS — protocol-based fake, in-memory CoreData, FakeURLProtocol за HTTP пресретање
  • Најбоља пракса — извуците fake у заједнички тест модул и користите у свим тестовима пројекта
  • Тестирајте fake — покрените исте тестове на fake и продукционој имплементацији за проверу конзистентности

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође