La biblioteca de pruebas de Health Connect (androidx.health.connect:connect-testing
) simplifica la creación de pruebas automatizadas. Puedes usar esta biblioteca para verificar el comportamiento de tu aplicación y validar que responda correctamente a casos poco comunes, que son difíciles de probar de forma manual.
Puedes usar la biblioteca para crear pruebas de unidades locales, que suelen verificar el comportamiento de las clases de tu app que interactúan con el cliente de Health Connect.
Para comenzar a usar la biblioteca, agrégala como dependencia de prueba:
testImplementation("androidx.health.connect:connect-testing:1.0.0-alpha01")
El punto de entrada a la biblioteca es la clase FakeHealthConnectClient
, que usas en las pruebas para reemplazar el objeto HealthConnectClient
. FakeHealthConnectClient
tiene las siguientes características:
- Una representación en memoria de los registros, para que puedas insertarlos, quitarlos, borrarlos y leerlos
- Generación de tokens de cambio y seguimiento de cambios
- Paginación de registros y cambios
- Las respuestas de agregación se admiten con stubs
- Permite que cualquier función arroje excepciones
- Un objeto
FakePermissionController
que se puede usar para emular verificaciones de permisos
Para obtener más información sobre el reemplazo de dependencias en las pruebas, consulta Inserción de dependencias en Android. Para obtener más información sobre los objetos simulados, consulta Cómo usar pruebas dobles en Android.
Por ejemplo, si la clase que interactúa con el cliente se llama HealthConnectManager
y toma un HealthConnectClient
como dependencia, se vería de la siguiente manera:
class HealthConnectManager(
private val healthConnectClient: HealthConnectClient,
...
) { }
En las pruebas, puedes pasar un objeto falso a la clase en prueba:
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)
}
}
Esta prueba verifica que la función ficticia fetchReport
en HealthConnectManager
filtre correctamente los registros por actividad.
Verifica excepciones
Casi todas las llamadas a HealthConnectClient
pueden generar excepciones. Por ejemplo, la documentación de insertRecords
menciona estas excepciones:
@throws android.os.RemoteException
para cualquier falla de transporte de IPC.@throws SecurityException
para las solicitudes con acceso no permitido.@throws java.io.IOException
para cualquier problema de E/S de disco.
Estas excepciones abarcan casos como una mala conexión o falta de espacio en el dispositivo. Tu app debe reaccionar correctamente a estos problemas de tiempo de ejecución, ya que pueden ocurrir en cualquier 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)
}
Agregación
Las llamadas de agregación no tienen implementaciones falsas. En cambio, las llamadas de agregación usan stubs que puedes programar para que se comporten de una manera determinada. Puedes acceder a los stubs a través de la propiedad overrides
de FakeHealthConnectClient
.
Por ejemplo, puedes programar la función de agregación para que devuelva un 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)
Luego, puedes verificar que la clase bajo prueba, HealthConnectManager
en este caso, procesó el resultado correctamente:
// 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)
Permisos
La biblioteca de pruebas incluye un FakePermissionController
, que se puede pasar como dependencia a FakeHealthConnectClient
.
El sujeto de prueba puede usar la propiedad PermissionController—through
de la interfaz permissionController
para verificar los permisos.HealthConnectClient
Por lo general, esto se hace antes de cada llamada al cliente.
Para probar esta función, puedes configurar los permisos disponibles con 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)
}
Paginación
La paginación es una fuente muy común de errores, por lo que FakeHealthConnectClient
proporciona mecanismos para ayudarte a verificar que tu implementación de paginación para registros y cambios se comporte correctamente.
Tu sujeto de prueba, HealthConnectManager
en nuestro ejemplo, puede especificar el tamaño de la página en ReadRecordsRequest
:
fun fetchRecordsReport(pageSize: Int = 1000) }
val pagedRequest =
ReadRecordsRequest(
timeRangeFilter = ...,
recordType = ...,
pageToken = page1.pageToken,
pageSize = pageSize,
)
val page = client.readRecords(pagedRequest)
...
Si estableces el tamaño de la página en un valor pequeño, como 2, puedes probar la paginación. Por ejemplo, puedes insertar 5 registros para que readRecords
devuelva 3 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)
}
Datos de pruebas
La biblioteca aún no incluye APIs para generar datos falsos, pero puedes usar los datos y los generadores que usa la biblioteca en Android Code Search.
Para simular valores de metadatos en pruebas, puedes usar MetadataTestHelper
. Esto proporciona la función de extensión populatedWithTestValues()
, que simula que Health Connect completa los valores de metadatos durante la inserción de registros.
Stubs
La propiedad overrides
de FakeHealthConnectClient
te permite programar (o crear stubs) cualquiera de sus funciones para que arrojen excepciones cuando se las llame.
Las llamadas de agregación también pueden devolver datos arbitrarios y admiten la puesta en cola de varias respuestas. Consulta Stub
y MutableStub
para obtener más información.
Resumen de los casos extremos
- Verifica que tu app se comporte como se espera cuando el cliente arroja excepciones. Consulta la documentación de cada función para saber qué excepciones debes verificar.
- Verifica que cada llamada que realices al cliente esté precedida por la verificación de permisos adecuada.
- Verifica la implementación de la paginación.
- Verifica qué sucede cuando recuperas varias páginas, pero una tiene un token vencido.