Fake — o que é, propósito e como usar em testes

Autor: IT Sectr Publicado: 2026-04-10 Tempo de leitura: 9 min

Fake é uma implementação simplificada e funcional de uma dependência que se comporta como um componente real, mas usa armazenamento em memória ou outros mecanismos leves em vez da infraestrutura de produção. Ao contrário de um stub, um fake contém lógica de negócio real — ordenação, filtragem, agregação — apenas sem efeitos externos. Um banco de dados em memória em vez de Room ou um HashMap em vez de SharedPreferences são exemplos clássicos. Mais detalhes em classificação de test doubles de Martin Fowler.

Principais pontos

  • Fake — uma implementação simplificada e funcional com lógica real, mas sem dependências externas
  • Armazenamento em memória — um repositório fake armazena dados em um HashMap em vez de um BD
  • Diferença de Stub — stub retorna dados fixos, fake contém lógica executável
  • Android — InMemoryUserRepository como Fake para testar ViewModel e UseCase
  • iOS — FakeNetworkSession com URLProtocol e dados de teste em vez de um servidor real

O que é um Fake e por que ele é necessário em testes?

Fake é uma implementação completa, mas leve, de uma interface, adequada para testes. O termo foi introduzido por Gerard Meszaros (2007) no livro “xUnit Test Patterns.” Ao contrário de um stub, que retorna respostas fixas, um fake contém código executável: pode ordenar uma lista, filtrar por condição, contar registros. A única diferença da implementação de produção é que um fake trabalha com dados em memória e não realiza operações reais de E/S.

A principal vantagem é a velocidade. Testes com um fake são executados em milissegundos porque não há acesso a disco, rede ou banco de dados. Um HashMap em memória funciona 100–1000 vezes mais rápido que Room ou CoreData. Ao mesmo tempo, um fake testa a lógica de negócio real: ordenação, filtragem, agregação — tudo o que um stub não pode testar porque ele apenas retorna o que lhe foi dito. Um fake dá confiança de que o código processa dados corretamente, em vez de apenas receber uma resposta pré-determinada.

Quando Fake é preferível a Stub

Fake é preferível a Stub — se o componente sob teste realiza múltiplas operações em dados (recuperar, filtrar, ordenar, salvar), um stub exigiria configurar cada chamada individualmente. Um fake contém a lógica internamente — o teste simplesmente chama métodos e verifica o resultado. Na IT Sectr, usamos fakes para todos os repositórios em testes unitários: um repositório fake com um HashMap cobre 90% dos cenários sem configurar Mockito ou MockK.

Fake vs Stub vs Mock: quando escolher o quê

Critério de seleção — determine o que o teste verifica: estado ou interação. Se o teste verifica estado (o resultado do trabalho) e usa lógica — use um fake. Se o teste precisa apenas de dados de entrada sem lógica — um stub é suficiente. Se o teste verifica que um método foi chamado — use um mock. Misturar tipos de test doubles em um teste complica o entendimento e aumenta a fragilidade.

CritérioFakeStubMock
Tem lógicaSim (simplificada)NãoNão
VelocidadeAltaMáximaAlta
Verificação de comportamentoIndiretaNãoSim (verify)
ManutençãoUma classe por interfaceConfigurar por testeConfigurar por teste
RealismoAlto (código funciona)Baixo (dados fixos)Médio
Risco de falsos positivosBaixoMédioAlto (testes frágeis)

Antipadrão: Fake que não é fake — um erro comum quando um desenvolvedor chama de fake um objeto que é na verdade um stub ou mock. Se seu InMemoryUserRepository não contém lógica (filtragem, ordenação) — não é um fake, mas um stub com armazenamento em memória. Um fake difere de um stub precisamente pela presença de lógica executável. Se um repositório fake simplesmente retorna o que foi colocado nele e não processa dados — use um mock ou stub.

Regra prática para escolher um Test Double

Recomendação prática — comece com um fake para cada repositório ou serviço. Se um fake ultrapassar 50 linhas — divida-o em várias classes. Se um fake não for necessário (o teste verifica apenas um único cenário com dados fixos) — use um stub. Se o teste verifica que um método foi chamado com parâmetros específicos — use um mock. Não otimize a escolha antecipadamente: escreva um fake e, se ele se mostrar excessivo, substitua-o por um stub em um teste específico.

Criação de objetos Fake no Android para Room e Retrofit

Repositório fake para Room — um exemplo típico de fake no Android. A implementação de produção do UserRepository usa Room DAO com consultas SQLite. A versão fake armazena dados em um MutableList ou HashMap e implementa os mesmos métodos: getUser(id), saveUser(user), deleteUser(id). O fake contém lógica de busca, filtragem e ordenação — igual ao repositório de produção, mas sem SQL. Isso permite testar ViewModel e UseCase sem configurar um banco de dados 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 para API Retrofit — em vez de MockWebServer (que é um stub, não um fake), você pode criar uma implementação de ApiService que retorna dados de uma coleção em memória. A diferença: MockWebServer intercepta HTTP e retorna JSON, enquanto um fake ApiService funciona no nível da interface Kotlin sem serialização. Um fake é mais rápido (sem análise JSON) e mais fácil de depurar (roda no mesmo processo, tipado). Adequado para testes onde a semântica HTTP (códigos de status, cabeçalhos) não é importante.

FakeSharedPreferences para testes rápidos

— outro cenário comum. SharedPreferences de produção escreve em disco via commit/apply. A versão fake armazena pares chave-valor em um HashMap e retorna dados instantaneamente. Suporta os mesmos métodos: getString, putString, getInt, putInt, clear. Para Jetpack DataStore, o análogo é FakeDataStore com armazenamento em memória. Esses fakes aceleram os testes dezenas de vezes porque não há operações de escrita em disco.

Implementações Fake no iOS com armazenamento em memória

Fake em Swift — é construído através de protocolos. A classe de produção implementa o protocolo com lógica real (CoreData, URLSession). A estrutura fake implementa o mesmo protocolo com armazenamento em memória e lógica simplificada. Swift é uma linguagem com semântica de valor, portanto as estruturas fake são imutáveis e seguras em testes multithread. Isso dá uma vantagem sobre os análogos Android: não há necessidade de sincronizar o acesso aos dados em memória.

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 para CoreData — em projetos iOS, você pode criar um NSPersistentContainer em memória configurando description.type = NSInMemoryStoreType. Isso é uma pilha CoreData completa, mas funcionando em memória. Esse fake permite testar NSFetchRequest, predicados e ordenações sem criar um arquivo SQLite. Velocidade: testes em CoreData em memória são executados 5–10 vezes mais rápido que no análogo em disco. A desvantagem: é necessário configurar NSManagedObjectModel cada vez.

FakeURLProtocol — uma subclasse de URLProtocol para interceptar requisições de rede no iOS. É registrada via URLProtocol.registerClass(fakeProtocol). Internamente contém um dicionário URL -> Data em memória e retorna dados sem uma requisição real. A diferença de um stub: FakeURLProtocol pode verificar o corpo da requisição, cabeçalhos e retornar diferentes respostas dependendo dos dados de entrada. Isso é um fake porque contém lógica de roteamento de requisições.

Padrões de uso de Fake em projetos móveis

Fake como Test Fixture — coloque as classes fake em um módulo de teste compartilhado (androidTest/sharedTest ou TestSupport). Todos os testes do projeto usam o mesmo InMemoryUserRepository. Isso elimina a duplicação de configuração de objetos mock em cada teste e garante comportamento uniforme. Alterar a lógica do fake atualiza todos os testes simultaneamente. Na IT Sectr, armazenamos classes fake em sharedTest/java/com/itSectr/fake/ e as incluímos via implementation project(:sharedTest).

Fake com dados predefinidos — frequentemente os testes precisam de um repositório que já contenha alguns registros. Solução: um método de fábrica fakeWithData(vararg items) ou um método embutido addDefaultData(). A fábrica cria um fake, preenche com dados típicos e retorna um objeto pronto para uso. Isso reduz boilerplate nos testes: em vez de configurar chamadas mock, o teste simplesmente chama FakeUserRepository.withUsers(alice, bob).

Fake com contagem de chamadas — às vezes é necessário verificar não apenas o estado, mas também o número de invocações. Um fake pode conter contadores: saveCallCount, getUserCallCount. O teste verifica o contador após a execução. Isso é um compromisso entre um fake puro (verificação de estado) e um mock (verificação de interação). Contadores não verificam argumentos ou ordem de chamadas — apenas a quantidade. Para verificação de argumentos, use um mock.

Fake com Callback — para testar cenários assíncronos, um fake pode aceitar um callback em cada chamada: beforeGetUser, afterSaveUser. Isso permite simular atrasos, erros ou verificar estados intermediários. Esta abordagem é útil para testar estados de carregamento da UI: o fake faz uma pausa de 100 ms e o teste verifica se a tela mostra um loader. O callback está ausente em produção — isso é funcionalidade puramente de teste.

Perguntas frequentes

Qual a diferença entre Fake e Stub?

Fake contém lógica funcional — filtra, ordena, conta. Stub apenas retorna respostas predeterminadas sem lógica. Se um objeto tem ramificações (if/else, when) — é um fake. Se ele contém apenas valores de retorno — é um stub. Fake é mais caro de manter, mas fornece testes mais realistas.

Quando um fake pode ser prejudicial?

Quando a lógica do fake não corresponde à lógica de produção. Por exemplo, FakeUserRepository usa busca case-sensitive, enquanto a versão de produção é case-insensitive. O teste passa, mas na realidade há um bug. Solução: teste a lógica do fake separadamente ou use fakes apenas para interfaces com lógica simples (operações CRUD). Para lógica complexa, escreva testes de integração com um banco de dados real.

Fake é a mesma coisa que banco de dados em memória?

Banco de dados em memória é um tipo de fake. Room.inMemoryDatabaseBuilder() cria SQLite em memória que se comporta como um banco de dados de produção. Isso é um fake completo. Mas um fake também pode estar no nível de repositório (sem SQL) e no nível de rede (FakeApiService). Um banco de dados em memória é um caso especial de fake onde a lógica está o mais próximo possível da realidade.

Posso combinar Fake e Mock em um teste?

Sim, mas com cautela. Fake para o repositório (dados), Mock para AnalyticsTracker (verificação de eventos). Separação por camadas: fake para a camada de dados, mock para a camada de análise/log. Não faça um objeto ser fake e mock ao mesmo tempo — isso viola o Princípio da Responsabilidade Única e confunde o teste.

Como testar o próprio Fake?

Teste o fake com os mesmos testes da implementação de produção. Se você tem um UserRepositoryTest que verifica save, get, delete — execute-o duas vezes: com FakeUserRepository e com RealUserRepository. Isso garante que o fake replica o comportamento da classe de produção. Se o fake começar a se comportar de maneira diferente — o teste falhará em ambas as implementações.

Resumo

  • Fake — uma implementação simplificada e funcional de uma dependência com lógica de negócio real e armazenamento em memória
  • Diferença de Stub — fake contém lógica (filtragem, ordenação), stub apenas retorna dados
  • Velocidade — fake funciona 100–1000 vezes mais rápido que a implementação de produção sem operações de E/S
  • Android — InMemoryUserRepository, FakeDataStore, Room em memória via Room.inMemoryDatabaseBuilder
  • iOS — fake baseado em protocolos, CoreData em memória, FakeURLProtocol para interceptação HTTP
  • Melhor prática — coloque fakes em um módulo de teste compartilhado e use em todos os testes do projeto
  • Teste o fake — execute os mesmos testes no fake e na implementação de produção para verificar consistência

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também