Stub: o que é, tipos e uso em testes

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

Stub (stub, dublê de teste) — um objeto de teste que retorna respostas predefinidas para chamadas de método em vez de uma implementação real. No desenvolvimento móvel, stubs isolam o módulo testado de requisições de rede, bancos de dados e sistemas de arquivos, permitindo verificar a lógica sem configuração de ambiente. Ao contrário de mock, stub não verifica comportamento — ele apenas fornece dados. Mais detalhes no artigo de Martin Fowler sobre test doubles.

Principais pontos

  • Stub — um dublê de teste que retorna valores predefinidos em chamadas de método sem lógica
  • Isolamento — stubs desativam dependências reais: API, BD, arquivos, sensores
  • Diferença de Mock — stub não verifica chamadas, ele apenas substitui a resposta
  • Android — MockWebServer (OkHttp) como stub para HTTP, MockK.constantAnswer para Kotlin
  • iOS — OCMock e protocolos Swift com implementações de teste como stubs

O que é um Stub e como difere de outros test doubles?

Stub é um objeto dublê de teste que substitui uma dependência real em um teste e retorna valores predefinidos para chamadas específicas. O termo foi introduzido na classificação de Gerard Meszaros (2007) no livro «xUnit Test Patterns». Stub pertence à categoria de test doubles — objetos que substituem componentes reais durante os testes. O objetivo principal de um stub é fornecer à unidade testada dados previsíveis, eliminando a incerteza dos sistemas externos.

Como funciona — o teste configura o stub antes da execução: «quando o método getUsers() for chamado, retorne esta lista de usuários». Stub não contém lógica de negócio, não verifica a ordem das chamadas nem registra o histórico. Ele simplesmente fica no lugar do componente real e retorna o que foi instruído. No contexto de testes Android, isso significa: o cliente OkHttp não faz uma requisição real ao servidor, mas recebe uma resposta do MockWebServer configurado como stub.

  • Stub — retorna dados, não verifica chamadas
  • Mock — retorna dados e verifica comportamento (verify)
  • Fake — implementação simplificada funcional com lógica real
  • Spy — envolve um objeto real, registrando chamadas
  • Dummy — é passado mas não usado (null, objeto vazio)

Quando usar — stubs são ideais para testar a camada de UI (ViewModel, Presenter) e lógica de negócio (UseCase, Interactor), onde é necessário verificar a reação a dados específicos: lista vazia, servidor retornou erro 500, token expirado. Qualquer caso onde o teste exija um estado de entrada específico é tarefa para stub. Cada cenário de teste tem sua própria configuração de stub, tornando os testes legíveis e previsíveis.

Classificação de test doubles segundo Meszaros

Gerard Meszaros (2007) no livro «xUnit Test Patterns» identificou cinco tipos de test doubles: dummy, stub, spy, mock, fake. Cada tipo resolve seu problema. Dummy — é passado mas não usado. Stub — retorna dados. Spy — registra chamadas. Mock — verifica comportamento. Fake — contém lógica simplificada. Compreender esta classificação ajuda o desenvolvedor a escolher a ferramenta certa para cada cenário de teste.

Onde stubs são usados em testes de aplicativos móveis

Stubs para requisições de rede

Requisições de rede — o cenário mais comum para uso de stubs. O aplicativo faz chamadas HTTP à API, e o teste precisa verificar a reação a diferentes respostas: JSON bem-sucedido, erro 401 (não autorizado), tempo limite, array vazio. MockWebServer (OkHttp) no Android e URLProtocol (iOS) atuam como stubs, retornando respostas HTTP predefinidas sem conexão real com o servidor. Isso acelera os testes de segundos para milissegundos.

Banco de dados — Room (Android) e CoreData (iOS) têm variantes in-memory, mas sua configuração ainda leva tempo. Stub em vez do repositório retorna listas de Entity preparadas sem tocar no BD. Isso é especialmente eficaz para testar ViewModel, onde é necessário verificar ordenação, filtragem ou transformação de dados. O teste executa em milissegundos independentemente do volume de dados.

Serviços do sistema — LocationManager, SensorManager, SharedPreferences exigem um dispositivo real ou emulador. Stub para LocationProvider retorna coordenadas predefinidas, para SensorManager — valores fixos do acelerômetro. No iOS, o equivalente é CLLocationManager com uma implementação de delegado de teste. Sem stubs, esses testes exigem um dispositivo físico com condições específicas.

Sistema de arquivos e cache — carregamento de imagens, cache de respostas, trabalho com arquivos de configuração — todas essas operações dependem do estado do disco. Stub para FileManager ou ImageCache retorna sucesso/erro sem ler arquivos reais. Isso elimina falhas falsas em testes devido a discrepâncias de caminhos ou direitos de acesso em diferentes máquinas de desenvolvimento.

Stub vs Mock vs Fake: diferenças principais

Divisão de responsabilidades — três tipos de test doubles resolvem tarefas diferentes. Stub: «me dê dados». Mock: «verifique que fui chamado». Fake: «funciono como o real, só que mais simples». A diferença é crítica para a legibilidade dos testes: se um teste usa mock onde precisa de stub, ele fica sobrecarregado com chamadas verify não relacionadas ao cenário testado.

CaracterísticaStubMockFake
PropósitoFornecer dadosVerificar interaçãoImplementação simplificada
LógicaNãoNãoSim (mas simplificada)
VerificaçãoNãoSim (verify)Indireta (via estado)
FlexibilidadeBaixa — respostas fixasMédiaAlta — lógica adapta
VelocidadeMáximaAltaMédia
ExemploMockWebServer retorna JSONMockito.verify(repository).save()InMemoryRepository com HashMap

Regra prática — se o teste verifica quais dados o componente testado recebeu — use stub. Se o teste verifica se o componente chamou o método da dependência com os argumentos corretos — use mock. Se você simplesmente quer substituir um BD por uma tabela hash — isso é fake. Misturar tipos em um mesmo teste o torna frágil: ao mudar a implementação, você terá que reescrever tanto a lógica de stub quanto de verify.

Antipadrão: Stub com verify

Stub com verify — um erro comum onde o desenvolvedor configura um stub e depois adiciona verify(stub).method(). Stub por definição não deve ser verificado — para isso existe mock. Se você precisa verificar que um método foi chamado com argumentos específicos, use Mockito.mock() em vez de Mockito.stub(). Essa separação mantém a intenção do teste clara para outros desenvolvedores.

Implementação de stubs no Android com MockWebServer e MockK

MockWebServer — uma biblioteca OkHttp para criar stubs HTTP no Android e JVM. Inicia um servidor HTTP local em uma porta especificada que intercepta as requisições do cliente OkHttp e retorna respostas predefinidas. A configuração leva três linhas: criar o servidor, enfileirar a resposta, iniciá-lo. O teste pode enfileirar sequencialmente várias respostas para cenários com paginação ou tentativas.

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 — uma alternativa ao Mockito para Kotlin com suporte de primeira classe para corrotinas, funções de extensão e classes seladas. Stubs no MockK são criados via coEvery (para funções suspend) e every (para funções regulares). Ao contrário do MockWebServer, o MockK stub métodos de dependência individuais em vez de toda a camada HTTP. Isso é útil para testes unitários de UseCase ou Interactor, onde as dependências são abstrações de repositórios.

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() }
    }
}

Melhores práticas — para testes de integração use MockWebServer (intercepta HTTP real), para testes unitários use MockK (stub interfaces). Não stube o que você não está testando: se o teste verifica o Repository, não stube o cliente OkHttp dentro dele — use um MockWebServer real no nível HTTP. Essa regra mantém os testes relevantes e reduz a fragilidade durante a refatoração.

Implementação de stubs no iOS com OCMock e protocolos

Protocolos Swift como stubs — na abordagem nativa do iOS, o stub é implementado substituindo uma estrutura de teste que está em conformidade com o protocolo da dependência. Em vez de um NetworkService real, o teste recebe um StubNetworkService que retorna dados fixos. Swift é uma linguagem com tipagem estática, portanto o stub deve estar em conformidade com o mesmo protocolo que o serviço real. O compilador garante que o stub implementa todos os métodos necessários.

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 para Objective-C — uma biblioteca para criar stubs e mocks em projetos iOS legados. OCMock suporta métodos stub com argumentos e valores de retorno. Projetos modernos em Swift preferem uma abordagem baseada em protocolos com stubs manuais — isso dá controle sobre cada método e não requer dependências externas. OCMock continua sendo uma opção para projetos onde protocolizar todas as dependências não é economicamente viável.

URLProtocol para stubs HTTP — um mecanismo do sistema no iOS para interceptar requisições de rede através de uma subclasse de URLProtocol. O teste registra um URLProtocol personalizado que intercepta URLSession e retorna respostas stub. A vantagem sobre stubs manuais: você não precisa mudar a arquitetura do aplicativo — URLSession permanece real, mas os dados são substituídos no nível do protocolo. A desvantagem: é mais difícil de depurar do que um serviço stub explícito.

Perguntas frequentes

Como Stub difere de Mock?

Stub retorna dados predefinidos e não verifica se uma chamada ocorreu. Mock adicionalmente verifica que o método foi chamado com os argumentos corretos (verify). Stub responde à pergunta «o que retornar», Mock responde a «a chamada foi feita». Use stub para verificação de estado, mock para verificação de interação.

Quando usar Fake em vez de Stub?

Fake é necessário quando o teste requer uma implementação funcional (embora simplificada) — por exemplo, um banco de dados in-memory em vez de Room. Stub é adequado para cenários únicos com dados predefinidos. Se você repete o mesmo stub em 10 testes — provavelmente você precisa de um Fake. Fake reduz a duplicação porque a lógica vive em uma única classe.

Métodos estáticos podem ser stubados?

No Android — MockK para objetos Kotlin (object) suporta mockkObject(), incluindo métodos estáticos de classes Java via mockkStatic(). No iOS — métodos estáticos do Swift não podem ser stubados diretamente; use protocolos e DI para substituir uma chamada static por um método de instância de um protocolo. Stubs estáticos são débito técnico e devem ser evitados em código novo.

Como stubar requisições de rede no Android?

Use MockWebServer (OkHttp) — funciona como um servidor HTTP local que enfileira respostas. Para Retrofit, basta substituir a URL base por localhost:8080. Para Ktor, use MockEngine — um mecanismo integrado para substituir HttpStatement. Ambas as abordagens funcionam sem internet real e dão controle total sobre o código de status, corpo e cabeçalhos da resposta.

Stub vs Spy — qual é a diferença?

Spy envolve um objeto real e registra chamadas, enquanto Stub substitui completamente o objeto por respostas fixas. Spy permite o uso parcial da implementação real (outros métodos funcionam como estão), enquanto stub não. Se você precisa verificar que um método foi chamado mas parte da lógica deve ser executada — use spy, não stub.

Resumo

  • Stub — um dublê de teste que retorna respostas predefinidas a chamadas de método durante os testes
  • Isolamento de dependências — stubs substituem requisições de rede, BD, serviços do sistema e sistema de arquivos
  • Diferença de Mock — stub não verifica chamadas, apenas retorna dados sem verificação de comportamento
  • Ferramentas Android — MockWebServer para HTTP, MockK para interfaces Kotlin com suporte a corrotinas
  • Ferramentas iOS — stubs baseados em protocolos no Swift, URLProtocol para HTTP, OCMock para Objective-C
  • Não misture papéis — não adicione verify a stub, use mock para verificação de chamadas
  • Stub + MockWebServer — abordagem padrão para testes de integração sem servidor real

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