Einheitentests mit der Health Connect-Testbibliothek erstellen

Health Connect-Testbibliothek (androidx.health.connect:connect-testing) vereinfacht die Erstellung automatisierter Tests. Sie können diese Bibliothek zur Bestätigung verwenden und überprüfen Sie, ob sie korrekt auf seltene Fälle, die manuell nur schwer zu testen sind.

Sie können die Bibliothek verwenden, um lokale Einheitentests zu erstellen, die normalerweise überprüfen, das Verhalten der Klassen in Ihrer App, die mit dem Health Connect Kundin/Kunde.

Wenn Sie die Bibliothek verwenden möchten, fügen Sie sie als Testabhängigkeit hinzu:

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

Der Einstiegspunkt in die Bibliothek ist die Klasse FakeHealthConnectClient, die Sie in Tests anstelle der HealthConnectClient verwenden. Das FakeHealthConnectClient verfügt über folgende Funktionen:

  • Eine speicherinterne Darstellung von Einträgen, die Sie einfügen, entfernen, löschen und lesen können
  • Generierung von Änderungstokens und Änderungs-Tracking
  • Paginierung für Einträge und Änderungen
  • Aggregationsantworten werden mit Stubs unterstützt
  • Ermöglicht es jeder Funktion, Ausnahmen zu werfen
  • Ein FakePermissionController, mit dem Berechtigungsprüfungen emuliert werden können

Weitere Informationen zum Ersetzen von Abhängigkeiten in Tests finden Sie unter Abhängigkeitsinjektion in Android Weitere Informationen zu Fakes finden Sie unter Test-Doubles unter Android verwenden.

Wenn beispielsweise die Klasse, die mit dem Client interagiert, HealthConnectManager und es nimmt HealthConnectClient als Abhängigkeit an, sieht so aus:

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

In Tests können Sie stattdessen einen Fake an die zu testende Klasse übergeben:

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

Mit diesem Test wird überprüft, ob die fiktive fetchReport-Funktion in HealthConnectManager Einträge ordnungsgemäß nach Aktivität filtert.

Ausnahmen prüfen

Bei fast jedem Aufruf von HealthConnectClient können Ausnahmen ausgelöst werden. In der Dokumentation für insertRecords werden beispielsweise folgende Ausnahmen erwähnt:

  • @throws android.os.RemoteException für alle IPC-Transportfehler.
  • @throws SecurityException für Anfragen mit uneingeschränktem Zugriff.
  • @throws java.io.IOException für etwaige Laufwerk-E/A-Probleme.

Diese Ausnahmen gelten für Fälle wie eine schlechte Verbindung oder kein Speicherplatz mehr auf dem . Ihre App muss auf diese Laufzeitprobleme richtig reagieren, da sie jederzeit auftreten können.

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

Zusammenfassung

Für Aggregationsaufrufe gibt es keine gefälschten Implementierungen. Stattdessen werden Aggregationsaufrufe Verwenden Sie Stubs, die Sie so programmieren können, dass sie sich auf eine bestimmte Weise verhalten. Sie können auf das Stubs über das Attribut overrides von FakeHealthConnectClient an.

Beispielsweise können Sie die Aggregatfunktion so programmieren, dass sie ein bestimmtes Ergebnis zurückgibt:

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)

Anschließend können Sie in dieser HealthConnectManager wurde das Ergebnis korrekt verarbeitet:

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

Berechtigungen

Die Testbibliothek enthält ein FakePermissionController, das übergeben werden kann. als Abhängigkeit von FakeHealthConnectClient.

Die Testperson kann die PermissionController—through verwenden, permissionController-Attribut der HealthConnectClient-Schnittstelle, um zu prüfen, nach Berechtigungen. Dies erfolgt normalerweise vor jedem Aufruf an den Kunden.

Um diese Funktionalität zu testen, können Sie mit 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)
}

Seitenumbruch

Die Paginierung ist eine häufige Ursache für Fehler. FakeHealthConnectClient stellt Mechanismen bereit, mit denen Sie überprüfen können, ob Ihre Paging-Implementierung für und Änderungen einwandfrei funktioniert.

Die Testperson, in unserem Beispiel HealthConnectManager, kann die Seitengröße im ReadRecordsRequest:

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

Wenn Sie die Seitengröße auf einen kleinen Wert wie 2 festlegen, können Sie die Paginierung ganz einfach testen. Sie können beispielsweise fünf Einträge einfügen, damit readRecords drei verschiedene Seiten zurückgibt:

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

Testdaten

Die Bibliothek enthält noch keine APIs zum Generieren von Fake-Daten. Sie können jedoch die von der Bibliothek verwendeten Daten und Generatoren in der Android Code Search verwenden.

Stubs

Mit der Eigenschaft overrides von FakeHealthConnectClient können Sie eine beliebige Funktion programmieren (oder auslagern), sodass beim Aufrufen Ausnahmen geworfen werden. Aggregationsaufrufe können auch beliebige Daten zurückgeben und unterstützen die Aufnahme in eine Warteschlange. mehrere Antworten geben. Weitere Informationen finden Sie unter Stub und MutableStub.

Zusammenfassung der Grenzfälle

  • Prüfen Sie, ob sich Ihre App wie erwartet verhält, wenn der Client Ausnahmen auslöst. Lesen Sie in der Dokumentation der einzelnen Funktionen nach, welche Ausnahmen überprüfen sollten.
  • Prüfe, ob vor jedem Aufruf des Clients die richtige Berechtigungsprüfung erfolgt.
  • Überprüfen Sie die Implementierung der Paginierung.
  • Prüfen Sie, was passiert, wenn Sie mehrere Seiten abrufen, eine davon aber ein abgelaufenes Token hat.