Um teste local é executado diretamente na sua estação de trabalho, e não em um dispositivo ou emulador Android. Por isso, ele usa a máquina virtual Java (JVM) local, em vez de um dispositivo Android, para executar testes. Os testes locais permitem avaliar a lógica do app com mais rapidez. No entanto, não poder interagir com o framework do Android cria uma limitação nos tipos de testes que você pode executar.
Um teste de unidade verifica o comportamento de uma pequena seção de código, a unidade em teste. Para isso, ele executa o código e verifica o resultado.
Os testes de unidade geralmente são simples, mas a configuração deles pode ser problemática quando a unidade em teste não é projetada com a testabilidade em mente:
- O código que você quer verificar precisa ser acessível em um teste. Por exemplo, não é possível testar um método particular diretamente. Em vez disso, teste a classe usando as APIs públicas dela.
- Para executar testes de unidade de forma isolada, as dependências da unidade em teste precisam ser substituídas por componentes que você controla, como simulações ou outros test doubles. Isso é especialmente problemático se o código depender do framework do Android.
Para saber mais sobre estratégias comuns de teste de unidade no Android, leia O que testar.
Local dos testes locais
Por padrão, os arquivos de origem dos testes de unidade locais são colocados em
module-name/src/test/. Esse diretório já existe quando você cria um novo
projeto usando o Android Studio.
Adicionar dependências de teste
Você também precisa configurar as dependências de teste para que seu projeto use as APIs padrão fornecidas pelo framework de teste JUnit.
Para fazer isso, abra o arquivo build.gradle do módulo do app e especifique as seguintes
bibliotecas como dependências. Use a função testImplementation para indicar
que elas se aplicam ao conjunto de origem do teste local, e não ao aplicativo:
dependencies {
// Required -- JUnit 4 framework
testImplementation "junit:junit:$jUnitVersion"
// Optional -- Robolectric environment
testImplementation "androidx.test:core:$androidXTestVersion"
// Optional -- Mockito framework
testImplementation "org.mockito:mockito-core:$mockitoVersion"
// Optional -- mockito-kotlin
testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion"
// Optional -- Mockk framework
testImplementation "io.mockk:mockk:$mockkVersion"
}
Criar uma classe de teste de unidade local
Você escreve sua classe de teste de unidade local como uma classe de teste JUnit 4.
Para fazer isso, crie uma classe que contenha um ou mais métodos de teste, geralmente em
module-name/src/test/. Um método de teste começa com a anotação @Test e
contém o código para exercitar e verificar um único aspecto do componente que
você quer testar.
O exemplo a seguir demonstra como implementar uma classe de teste de unidade local. O
método de teste emailValidator_correctEmailSimple_returnsTrue() tenta verificar
isValidEmail(),que é um método dentro do app. A função de teste vai retornar
true se isValidEmail() também retornar true.
Kotlin
import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Test class EmailValidatorTest { @Test fun emailValidator_CorrectEmailSimple_ReturnsTrue() { assertTrue(EmailValidator.isValidEmail("name@email.com")) } }
Java
import org.junit.Test; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; class EmailValidatorTest { @Test public void emailValidator_CorrectEmailSimple_ReturnsTrue() { assertTrue(EmailValidator.isValidEmail("name@email.com")); } }
Crie testes legíveis que avaliem se os componentes do seu
app retornam os resultados esperados. Recomendamos que você use uma biblioteca de declarações, como
junit.Assert, Hamcrest ou
Truth. O snippet acima é um exemplo de como usar
junit.Assert.
Biblioteca simulável do Android
Quando você executa testes de unidade locais, o Plug-in do Android para Gradle inclui uma biblioteca com todas as APIs do framework do Android, de acordo com a versão usada no seu projeto. A biblioteca contém todos os métodos e classes públicos dessas APIs, mas o código dentro dos métodos foi removido. Se algum dos métodos for acessado, o teste vai gerar uma exceção.
Isso permite que testes locais sejam criados ao referenciar classes no framework do Android, como Context. Mais importante ainda, ele permite que você use um framework de simulação
com classes do Android.
Simular dependências do Android
Um problema comum é descobrir que uma classe está usando um recurso de string. É possível
receber recursos de string chamando o método getString() na classe
Context. No entanto, um teste local não pode usar Context ou qualquer um dos métodos dele, porque eles
pertencem ao framework do Android. O ideal é que a chamada para getString() seja
movida para fora da classe, mas isso nem sempre é prático. A solução é
criar uma simulação ou um stub de Context que sempre retorne o mesmo valor quando o método
getString() for invocado.
Com a biblioteca simulável do Android e frameworks de simulação, como Mockito ou MockK, é possível programar o comportamento de simulações das classes do Android nos testes de unidade.
Para adicionar um objeto simulado ao teste de unidade local usando o Mockito, siga este modelo de programação:
- Inclua a dependência da biblioteca Mockito no arquivo
build.gradle, conforme descrito em Configurar o ambiente de teste. - No início da definição da classe de teste de unidade, adicione a
anotação
@RunWith(MockitoJUnitRunner.class). Essa anotação informa ao executor de testes do Mockito para validar se o uso do framework está correto e simplifica a inicialização dos objetos simulados. - Para criar um objeto simulado para uma dependência do Android, adicione a anotação
@Mockantes da declaração do campo. - Para simular o comportamento da dependência, especifique uma condição e
um valor de retorno quando a condição for atendida usando os métodos
when()ethenReturn().
O exemplo a seguir mostra como criar um teste de unidade que usa um objeto Context simulado em Kotlin criado com o Mockito-Kotlin.
import android.content.Context
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
private const val FAKE_STRING = "HELLO WORLD"
@RunWith(MockitoJUnitRunner::class)
class MockedContextTest {
@Mock
private lateinit var mockContext: Context
@Test
fun readStringFromContext_LocalizedString() {
// Given a mocked Context injected into the object under test...
val mockContext = mock<Context> {
on { getString(R.string.name_label) } doReturn FAKE_STRING
}
val myObjectUnderTest = ClassUnderTest(mockContext)
// ...when the string is returned from the object under test...
val result: String = myObjectUnderTest.getName()
// ...then the result should be the expected one.
assertEquals(result, FAKE_STRING)
}
}
Para saber mais sobre como usar o framework Mockito, consulte a referência da API
Mockito e a classe SharedPreferencesHelperTest no
exemplo de código. Confira também o codelab de testes do Android.
Erro: "Method ... not mocked"
A biblioteca simulável do Android gera uma exceção se você tentar acessar qualquer um dos
métodos dela com a mensagem Error: "Method ... not mocked.
Se as exceções geradas forem problemáticas para seus testes, mude o
comportamento para que os métodos retornem nulo ou zero, dependendo do
tipo de retorno. Para fazer isso, adicione a seguinte configuração no arquivo build.gradle de nível superior do seu projeto no Groovy:
android {
...
testOptions {
unitTests.returnDefaultValues = true
}