Biblioteca de testes do app Conexão Saúde (androidx.health.connect:connect-testing
)
simplifica a criação de testes automatizados. É possível usar essa biblioteca para verificar
o comportamento do aplicativo e validar se ele responde corretamente a
casos incomuns, que são difíceis de testar manualmente.
É possível usar a biblioteca para criar testes de unidade locais, que normalmente verificam o comportamento das classes no app que interagem com o cliente do Health Connect.
Para começar a usar a biblioteca, adicione-a como uma dependência de teste:
testImplementation("androidx.health.connect:connect-testing:1.0.0-alpha01")
O ponto de entrada para a biblioteca é a classe FakeHealthConnectClient
, que você
usado em testes para substituir o HealthConnectClient
. O FakeHealthConnectClient
tem os seguintes recursos:
- Uma representação de registros na memória, para que você possa inserir, remover, excluir e ler
- Geração de tokens de mudança e acompanhamento de mudanças
- Paginação de registros e mudanças
- As respostas de agregação têm suporte a stubs
- Permite que qualquer função gere exceções
- Um
FakePermissionController
que pode ser usado para emular verificações de permissões
Para saber mais sobre como substituir dependências em testes, leia Injeção de dependências no Android. Para saber mais sobre fakes, leia Uso de testes duplos no Android.
Por exemplo, se a classe que interage com o cliente for chamada
HealthConnectManager
e tiver um HealthConnectClient
como dependência, ela
vai ficar assim:
class HealthConnectManager(
private val healthConnectClient: HealthConnectClient,
...
) { }
Nos testes, é possível transmitir um valor falso para a classe em teste:
import androidx.health.connect.client.testing.ExperimentalTestingApi
import androidx.health.connect.client.testing.FakeHealthConnectClient
import kotlinx.coroutines.test.runTest
@OptIn(ExperimentalTestingApi::class)
class HealthConnectManagerTest {
@Test
fun readRecords_filterByActivity() = runTest {
// Create a Fake with 2 running records.
val fake = FakeHealthConnectClient()
fake.insertRecords(listOf(fakeRunRecord1, fakeBikeRecord1))
// Create a manager that depends on the fake.
val manager = HealthConnectManager(fake)
// Read running records only.
val runningRecords = manager.fetchReport(activity = Running)
// Verify that the records were filtered correctly.
assertTrue(runningRecords.size == 1)
}
}
Este teste verifica se a função fetchReport
fictícia em
HealthConnectManager
filtra corretamente os registros por atividade.
Como verificar exceções
Quase todas as chamadas para HealthConnectClient
podem gerar exceções. Por exemplo:
a documentação de insertRecords
menciona estas exceções:
@throws android.os.RemoteException
para qualquer falha de transporte da IPC.@throws SecurityException
para solicitações com acesso não permitido.@throws java.io.IOException
para problemas de E/S de disco.
Essas exceções abrangem casos como uma conexão ruim ou falta de espaço no dispositivo. Seu app precisa reagir corretamente a esses problemas de execução, já que eles podem acontecer a qualquer momento.
import androidx.health.connect.client.testing.stubs.stub
@Test
fun addRecords_throwsRemoteException_errorIsExposed() {
// Create Fake that throws a RemoteException
// when insertRecords is called.
val fake = FakeHealthConnectClient()
fake.overrides.insertRecords = stub { throw RemoteException() }
// Create a manager that depends on the fake.
val manager = HealthConnectManager(fake)
// Insert a record.
manager.addRecords(fakeRunRecord1)
// Verify that the manager is exposing an error.
assertTrue(manager.errors.size == 1)
}
Agregação
As chamadas de agregação não têm implementações falsas. Em vez disso, as chamadas de agregação
usar stubs que podem ser programados para se comportar de uma determinada maneira. Acesse o
usando a propriedade overrides
do FakeHealthConnectClient
.
Por exemplo, é possível programar a função agregada para retornar um resultado específico:
import androidx.health.connect.client.testing.AggregationResult
import androidx.health.connect.client.records.HeartRateRecord
import androidx.health.connect.client.records.ExerciseSessionRecord
import java.time.Duration
@Test
fun aggregate() {
// Create a fake result.
val result =
AggregationResult(metrics =
buildMap {
put(HeartRateRecord.BPM_AVG, 74.0)
put(
ExerciseSessionRecord.EXERCISE_DURATION_TOTAL,
Duration.ofMinutes(30)
)
}
)
// Create a fake that always returns the fake
// result when aggregate() is called.
val fake = FakeHealthConnectClient()
fake.overrides.aggregate = stub(result)
Em seguida, é possível verificar se a classe em teste, HealthConnectManager
, nesse
caso, processou o resultado corretamente:
// Create a manager that depends on the fake.
val manager = HealthConnectManager(fake)
// Call the function that in turn calls aggregate on the client.
val report = manager.getHeartRateReport()
// Verify that the manager is exposing an error.
assertThat(report.bpmAverage).isEqualTo(74.0)
Permissões
A biblioteca de teste inclui um FakePermissionController
, que pode ser transmitido
como uma dependência para FakeHealthConnectClient
.
O objeto em testes pode usar o PermissionController—through
propriedade permissionController
da interface HealthConnectClient
. Para verificar,
para saber as permissões. Isso normalmente é feito antes de cada chamada para o cliente.
Para testar essa funcionalidade, você pode definir quais permissões estão disponíveis usando
o FakePermissionController
:
import androidx.health.connect.client.testing.FakePermissionController
@Test
fun newRecords_noPermissions_errorIsExposed() {
// Create a permission controller with no permissions.
val permissionController = FakePermissionController(grantAll = false)
// Create a fake client with the permission controller.
val fake = FakeHealthConnectClient(permissionController = permissionController)
// Create a manager that depends on the fake.
val manager = HealthConnectManager(fake)
// Call addRecords so that the permission check is made.
manager.addRecords(fakeRunRecord1)
// Verify that the manager is exposing an error.
assertThat(manager.errors).hasSize(1)
}
Paginação
A paginação é uma fonte muito comum de bugs, então FakeHealthConnectClient
fornece mecanismos para ajudar a verificar se a implementação de paginação para
registros e alterações se comporta corretamente.
O sujeito em teste, HealthConnectManager
no nosso exemplo, pode especificar o
tamanho da página no ReadRecordsRequest
:
fun fetchRecordsReport(pageSize: Int = 1000) }
val pagedRequest =
ReadRecordsRequest(
timeRangeFilter = ...,
recordType = ...,
pageToken = page1.pageToken,
pageSize = pageSize,
)
val page = client.readRecords(pagedRequest)
...
Definir o tamanho da página com um valor pequeno, como 2, permite testar facilmente
paginação. Por exemplo, é possível inserir cinco registros para que readRecords
retorne três
páginas diferentes:
@Test
fun readRecords_multiplePages() = runTest {
// Create a Fake with 2 running records.
val fake = FakeHealthConnectClient()
fake.insertRecords(generateRunningRecords(5))
// Create a manager that depends on the fake.
val manager = HealthConnectManager(fake)
// Read records with a page size of 2.
val report = manager.generateReport(pageSize = 2)
// Verify that all the pages were processed correctly.
assertTrue(report.records.size == 5)
}
Dados de teste
A biblioteca ainda não inclui APIs para gerar dados falsos, mas você pode usar os dados e geradores usados pela biblioteca na Pesquisa de código do Android.
Stubs
A propriedade overrides
de FakeHealthConnectClient
permite programar (ou
criar um rascunho) qualquer uma das funções para que elas gerem exceções quando forem chamadas.
As chamadas de agregação também podem retornar dados arbitrários e oferece suporte ao enfileiramento
múltiplas respostas. Consulte Stub
e MutableStub
para mais informações.
Resumo dos casos extremos
- Verifique se o app se comporta conforme o esperado quando o cliente gera exceções. Consulte a documentação de cada função para descobrir quais exceções você precisa verificar.
- Verifique se todas as chamadas feitas para o cliente são precedidas pela verificação adequada de permissões.
- Verifique sua implementação de paginação.
- Verifique o que acontece quando você busca várias páginas, mas uma delas tem um token expirado.