Créer des tests unitaires à l'aide de la bibliothèque de tests Santé Connect

Bibliothèque de tests Santé Connect (androidx.health.connect:connect-testing) simplifie la création de tests automatisés. Vous pouvez utiliser cette bibliothèque pour vérifier le comportement de votre application et vérifier qu'elle répond correctement les cas rares, qui sont difficiles à tester manuellement.

Elle vous permet de créer des tests unitaires locaux, qui vérifient généralement le comportement des classes de votre application qui interagissent avec Santé Connect client.

Pour commencer à utiliser la bibliothèque, ajoutez-la en tant que dépendance de test:

 testImplementation("androidx.health.connect:connect-testing:1.0.0-alpha01")

Le point d'entrée de la bibliothèque est la classe FakeHealthConnectClient, que vous à utiliser dans les tests pour remplacer HealthConnectClient. FakeHealthConnectClient présente les caractéristiques suivantes:

  • Une représentation en mémoire des enregistrements, de sorte que vous pouvez insérer, supprimer, supprimer et les lire
  • Génération de jetons de modification et suivi des modifications
  • Pagination pour les enregistrements et les modifications
  • Les réponses d'agrégation sont compatibles avec les bouchons
  • Autorise toutes les fonctions à générer des exceptions
  • Un élément FakePermissionController qui peut être utilisé pour émuler des vérifications d'autorisations

Pour en savoir plus sur le remplacement des dépendances dans les tests, consultez Injection de dépendances dans Android. Pour en savoir plus sur les contrefaçons, consultez Utiliser des doubles de test sous Android

Par exemple, si la classe qui interagit avec le client est appelée HealthConnectManager et utilise un HealthConnectClient comme dépendance, il ressemblerait à ceci:

class HealthConnectManager(
    private val healthConnectClient: HealthConnectClient,
    ...
) { }

Lors des tests, vous pouvez transmettre un objet fictif à votre classe testée à la place:

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)
    }
}

Ce test vérifie que la fonction fetchReport fictive dans HealthConnectManager filtre correctement les enregistrements par activité.

Vérifier les exceptions

Presque tous les appels à HealthConnectClient peuvent générer des exceptions. Par exemple : La documentation pour insertRecords mentionne ces exceptions:

  • @throws android.os.RemoteException pour les échecs de transport IPC.
  • @throws SecurityException pour les requêtes avec accès non autorisé.
  • @throws java.io.IOException pour tout problème d'E/S de disque.

Ces exceptions s'appliquent en cas de mauvaise connexion ou de manque d'espace sur le appareil. Votre application doit réagir correctement à ces problèmes d'exécution, car ils peuvent à tout moment.

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)
}

Agrégation

Les appels d'agrégation n'ont pas d'implémentations fictives. À la place, les appels d'agrégation utiliser des bouchons que vous pouvez programmer pour qu’ils se comportent d’une certaine manière. Vous pouvez accéder bouchons via la propriété overrides de FakeHealthConnectClient.

Par exemple, vous pouvez programmer la fonction d'agrégation pour qu'elle renvoie un résultat spécifique:

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)

Vous pouvez ensuite vérifier que la classe testée, HealthConnectManager, dans ce a traité correctement le résultat:

// 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)

Autorisations

La bibliothèque de test inclut un FakePermissionController, qui peut être transmis en tant que dépendance à FakeHealthConnectClient.

Le sujet testé peut utiliser PermissionController—through le Propriété permissionController de l'interface HealthConnectClient, pour vérifier pour les autorisations. Cette opération est généralement effectuée avant chaque appel au client.

Pour tester cette fonctionnalité, vous pouvez définir les autorisations disponibles en utilisant le 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)
}

Pagination

La pagination est une source de bugs très courante. FakeHealthConnectClient fournit des mécanismes permettant de vérifier que votre implémentation de pagination pour les enregistrements et les modifications se comportent correctement.

Votre objet testé, HealthConnectManager dans notre exemple, peut spécifier le taille de page dans ReadRecordsRequest:

fun fetchRecordsReport(pageSize: Int = 1000) }
    val pagedRequest =
        ReadRecordsRequest(
            timeRangeFilter = ...,
            recordType = ...,
            pageToken = page1.pageToken,
            pageSize = pageSize,
        )
    val page = client.readRecords(pagedRequest)
    ...

Définir la taille de la page sur une valeur faible (2, par exemple) vous permet de tester facilement la pagination. Par exemple, vous pouvez insérer 5 enregistrements pour que readRecords renvoie 3 pages différentes:

@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)
}

Données de test

La bibliothèque n'inclut pas encore d'API permettant de générer des données fictives, mais vous pouvez utiliser la données et générateurs utilisés par la bibliothèque dans Android Code Search.

Souches

La propriété overrides de FakeHealthConnectClient vous permet de programmer bouchon) l'une de ses fonctions, de sorte qu'elles génèrent des exceptions lorsqu'elles sont appelées. Les appels d'agrégation peuvent également renvoyer des données arbitraires et prendre en charge la mise en file d'attente plusieurs réponses. Pour en savoir plus, consultez Stub et MutableStub.

Récapitulatif des cas limites

  • Vérifiez que votre application se comporte comme prévu lorsque le client génère des exceptions. Consultez la documentation de chaque fonction pour déterminer les exceptions que vous doit vérifier.
  • Vérifiez que chaque appel que vous effectuez au client est précédé de la chaîne vérification des autorisations.
  • Vérifiez l'implémentation de la pagination.
  • Vérifiez ce qui se passe lorsque vous extrayez plusieurs pages, mais que l'une d'elles a expiré à partir d'un jeton d'accès.