Quando você testa um elemento ou sistema de elementos, faz isso em isolamento. Por exemplo, para testar um ViewModel, você não precisa iniciar um emulador e lançar uma interface porque ele não depende (ou não deveria depender) do framework do Android.
No entanto, o sujeito em teste pode depender de outros para funcionar. Por exemplo, um ViewModel pode depender de um repositório de dados para funcionar.
Quando você precisa fornecer uma dependência para um objeto em teste, uma prática comum é criar um teste duplo (ou objeto de teste). As cópias de teste são objetos que aparentam e atuam como componentes no app, mas são criadas no teste para fornecer um comportamento ou dados específicos. A principal vantagem é que eles tornam os testes mais rápidos e simples.
Tipos de duplas de teste
Há vários tipos de duplas de teste:
Falso | Um teste duplo que tem uma implementação "funcional" da classe, mas é implementado de forma a ser bom para testes, mas inadequado para produção.
Exemplo: um banco de dados na memória. As falsificações não precisam de uma estrutura fictícia e são leves. Eles são preferencial. |
---|---|
Modelo | Um duplo de teste que se comporta da mesma forma que você o programa para se comportar e que tem expectativas sobre suas interações. Os modelos vão falhar nos testes se as interações não corresponderem aos requisitos definidos. Geralmente, as simulações são criadas com um framework de simulação para fazer tudo isso.
Exemplo: verifique se um método em um banco de dados foi chamado exatamente uma vez. |
Stub | Um duplo de teste que se comporta como você programou, mas não tem expectativas sobre as interações. Geralmente criado com um framework de simulação. As falsificações são preferidas em vez de stubs para simplificar. |
Fictício | 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 rastreia algumas informações adicionais, semelhante a mocks. Elas geralmente são evitadas porque adicionam complexidade. Portanto, é melhor usar falsificações ou simulações em vez de espiões. |
Sombra | Fake usado no Robolectric. |
Exemplo de uso de simulação
Suponha que você queira fazer um teste unitário de um ViewModel que depende de uma interface
chamada UserRepository
e expõe o nome do primeiro usuário para uma interface. É possível
criar um double de teste 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
fictício não precisa depender das fontes de dados
locais e remotas que a versão de produção usaria. O arquivo está no conjunto de origem
de teste e não é enviado com o app de produção.
O teste a seguir verifica se o ViewModel expõe corretamente o nome do primeiro 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 difícil substituir
elementos arbitrários em testes maiores.
Substituição de componentes e injeção de dependência
Quando os testes não têm controle sobre a criação dos sistemas em teste, substituir componentes por duplos de teste se torna mais complexo e exige que a arquitetura do app siga um design testável.
Até mesmo testes de ponta a ponta grandes podem se beneficiar do uso de duplos de teste, como um teste de interface instrumentado que navega por um fluxo de usuário completo no app. Nesse caso, talvez seja melhor tornar o 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 ter essa flexibilidade manualmente, mas recomendamos o uso de um framework de injeção de dependência, como o Hilt, para substituir componentes do app no momento do teste. Consulte o Guia de teste do Hilt.
Próximas etapas
A página Estratégias de teste mostra como melhorar sua produtividade usando diferentes tipos de testes.