Ao projetar a estratégia de teste para um elemento ou sistema, há três aspectos de teste relacionados:
- Escopo: quanto do código é tocado pelo teste? Os testes podem verificar um único método, o aplicativo inteiro ou algo intermediário. O escopo testado está em teste e geralmente se refere a ele como Assunto em teste, mas também como Sistema em teste ou Unidade em teste.
- Velocidade: com que rapidez o teste é executado? As velocidades de teste podem variar de milissegundos a vários minutos.
- Fidelidade: quanto o teste é "real"? Por exemplo, se parte do código que você está testando precisa fazer uma solicitação de rede, o código de teste realmente faz essa solicitação de rede ou falsifica o resultado? Se o teste realmente se comunicar com a rede, isso significa que ele tem maior fidelidade. A desvantagem é que o teste pode levar mais tempo para ser executado, resultar em erros se a rede estiver inativa ou pode ser caro para ser usado.
Consulte O que testar para saber como começar a definir sua estratégia de teste.
Isolamento e dependências
O teste de um elemento ou sistema de elementos é feito em isolamento. Por exemplo, para testar um ViewModel, você não precisa iniciar um emulador e iniciar uma IU, porque isso não depende (ou não deve) depender do framework do Android.
No entanto, o objeto em teste pode depender de outras para funcionar. Por exemplo, um ViewModel pode depender de um repositório de dados para funcionar.
Quando é necessário fornecer uma dependência para um objeto em teste, uma prática comum é criar um teste duplo (ou objeto de teste). Duplicatas de teste são objetos que parecem e funcionam como componentes no app, mas são criadas no teste para fornecer um comportamento ou dados específicos. As principais vantagens são que eles tornam os testes mais rápidos e simples.
Tipos de testes duplos
Há vários tipos de testes duplos:
Conteúdo falso | Uma dupla de teste que tem uma implementação da classe "funcionando", mas que é implementada de modo a ser boa para testes, mas inadequada para produção.
Exemplo: um banco de dados na memória. Os modelos não exigem uma estrutura de simulação e são leves. Eles são recomendados. |
---|---|
Simulação | Um teste duplo que se comporta da maneira como você o programa e que tem expectativas sobre as interações dele. As simulações falharão nos testes se as interações delas não corresponderem aos requisitos definidos. As simulações geralmente são criadas com uma estrutura de simulação (link em inglês) para fazer tudo isso.
Exemplo: verifique se um método em um banco de dados foi chamado exatamente uma vez. |
Stub | Um teste duplo que se comporta da maneira como você o programa, mas não tem expectativas sobre as interações dele. Geralmente criado com um framework de simulação. Para simplificar, é melhor usar falsificações em vez de stubs. |
Falso | Um teste duplo que é transmitido, mas não usado, por exemplo, se você só precisar fornecê-lo como um parâmetro.
Exemplo: uma função vazia transmitida como um callback de clique. |
Espião | Um wrapper sobre um objeto real que também monitora algumas informações adicionais, semelhantes a simulações. Elas geralmente são evitadas para aumentar a complexidade. Por isso, é melhor usar falsificações ou simulações em vez de espiões. |
Sombra | Falso usado no Robolectric. |
Exemplo de uso de uma instância
Suponha que você queira fazer um teste de unidade de um ViewModel que depende de uma interface
chamada UserRepository
e exponha o nome do primeiro usuário a uma IU. Você pode
criar um teste duplo falso implementando a interface e retornando dados
conhecidos.
object FakeUserRepository : UserRepository {
fun getUsers() = listOf(UserAlice, UserBob)
}
val const UserAlice = User("Alice")
val const UserBob = User("Bob")
Esse UserRepository
falso não precisa depender das fontes de dados locais e remotas
que a versão de produção usaria. O arquivo reside no conjunto de origem
de teste e não será enviado com o app de produção.

O teste a seguir verifica se o ViewModel expõe corretamente o primeiro nome de usuário à visualização.
@Test
fun viewModelA_loadsUsers_showsFirstUser() {
// Given a VM using fake data
val viewModel = ViewModelA(FakeUserRepository) // Kicks off data load on init
// Verify that the exposed data is correct
assertEquals(viewModel.firstUserName, UserAlice.name)
}
Substituir o UserRepository
por um falso é fácil em um teste de unidade, porque o
ViewModel é criado pelo testador. No entanto, pode ser desafiador substituir elementos arbitrários em testes maiores.
Como substituir componentes e injeção de dependência
Quando os testes não têm controle sobre a criação dos sistemas que estão sendo testados, a substituição de componentes por cópias de teste torna-se mais complexa e exige que a arquitetura do app siga um design testável.
Até mesmo grandes testes completos podem se beneficiar do uso de testes duplos, como um teste de IU instrumentado que navega por um fluxo de usuário completo no app. Nesse caso, convém tornar seu teste hermético. Um teste hermético evita todas as dependências externas, como a busca de dados da Internet. Isso melhora a confiabilidade e o desempenho.

Você pode projetar seu app para alcançar essa flexibilidade manualmente, mas recomendamos usar um framework de injeção de dependência, como o Hilt, para substituir componentes no momento do teste. Consulte o guia de teste do Hilt.
Robolectric
No Android, você pode usar o framework Robolectric, que fornece um tipo especial de teste duplo. O Robolectric permite executar testes na estação de trabalho ou no ambiente de integração contínua. Ele usa uma JVM normal, sem um emulador ou dispositivo. Ele simula a inflação de visualizações, o carregamento de recursos e outras partes do framework do Android com cópias de teste chamadas de sombras.
O Robolectric é um simulador. Portanto, não deve substituir testes de unidade simples nem ser usado para fazer testes de compatibilidade. Ele fornece velocidade e reduz os custos à custa de menor fidelidade em alguns casos. Uma boa abordagem para testes de IU é torná-los compatíveis com testes Robolectric e instrumentados e decidir quando executá-los, dependendo da necessidade de testar a funcionalidade ou compatibilidade. Tanto os testes do Espresso quanto do Compose podem ser executados no Robolectric.