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 a um objeto em teste, uma prática comum é criar uma cópia de teste (ou um objeto de teste). Test doubles são objetos que parecem e agem como componentes no app, mas são criados no teste para fornecer um comportamento ou dados específicos. As principais vantagens são que eles tornam seus testes mais rápidos e simples.
Tipos de duplas de teste
Há vários tipos de duplas de teste:
Falso | Um duplo de teste que tem uma implementação "funcional" da classe, mas que é implementado de uma maneira que o torna bom para testes, mas inadequado para produção.
Exemplo: um banco de dados na memória. Os fakes não exigem um framework de simulação e são leves. Eles são preferencial. |
---|---|
Modelo | Um duplo de teste que se comporta como você programou e que tem expectativas sobre as interações. Os modelos vão falhar nos testes se as interações não corresponderem aos requisitos definidos. Os modelos geralmente são criados com um mocking framework para conseguir 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 duplo de teste que é transmitido, mas não usado, como se você precisasse apenas 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 usando uma falsificaçã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
falso 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.
É possível projetar o 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 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 a produtividade usando diferentes tipos de testes.