Die Health Connect-Testbibliothek (androidx.health.connect:connect-testing
) vereinfacht die Erstellung automatisierter Tests. Mit dieser Bibliothek können Sie das Verhalten Ihrer Anwendung überprüfen und validieren, dass sie korrekt auf ungewöhnliche Fälle reagiert, die manuell schwer zu testen sind.
Mit der Bibliothek können Sie lokale Unittests erstellen, mit denen in der Regel das Verhalten der Klassen in Ihrer App überprüft wird, die mit dem Health Connect-Client interagieren.
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 verwenden, um die HealthConnectClient
zu ersetzen. FakeHealthConnectClient
bietet die folgenden Funktionen:
- Eine speicherinterne Darstellung von Datensätzen, sodass Sie sie einfügen, entfernen, löschen und lesen können
- Generierung von Änderungs-Tokens und Änderungs-Tracking
- Paginierung für Datensätze und Änderungen
- Aggregation-Antworten werden mit Stubs unterstützt
- Ermöglicht, dass jede Funktion Ausnahmen auslösen kann
- Ein
FakePermissionController
, mit dem Berechtigungsprüfungen emuliert werden können
Weitere Informationen zum Ersetzen von Abhängigkeiten in Tests finden Sie unter Dependency Injection in Android. Weitere Informationen zu Fakes finden Sie unter Test-Doubles in Android verwenden.
Wenn die Klasse, die mit dem Client interagiert, beispielsweise HealthConnectManager
heißt und eine HealthConnectClient
als Abhängigkeit verwendet, sieht das so aus:
class HealthConnectManager(
private val healthConnectClient: HealthConnectClient,
...
) { }
In Tests können Sie stattdessen ein 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)
}
}
In diesem Test wird überprüft, ob die fiktive Funktion fetchReport
in HealthConnectManager
Datensätze ordnungsgemäß nach Aktivität filtert.
Ausnahmen überprüfen
Bei fast jedem Aufruf von HealthConnectClient
können Ausnahmen ausgelöst werden. In der Dokumentation für insertRecords
werden beispielsweise die folgenden Ausnahmen erwähnt:
@throws android.os.RemoteException
für alle IPC-Übertragungsfehler.@throws SecurityException
für Anfragen mit unzulässigem Zugriff.@throws java.io.IOException
für alle Probleme mit der Laufwerk-E/A.
Diese Ausnahmen decken Fälle wie eine schlechte Verbindung oder nicht genügend Speicherplatz auf dem Gerät ab. Ihre App muss korrekt auf diese Laufzeitprobleme 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 bei Aggregationsaufrufen Stubs verwendet, die Sie so programmieren können, dass sie sich auf bestimmte Weise verhalten. Sie können über die overrides
-Property des FakeHealthConnectClient
auf die Stubs zugreifen.
Sie können die Aggregatfunktion beispielsweise 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 prüfen, ob die zu testende Klasse, in diesem Fall HealthConnectManager
, das Ergebnis korrekt verarbeitet hat:
// 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 als Abhängigkeit an FakeHealthConnectClient
übergeben werden kann.
Das zu testende Subjekt kann die PermissionController—through
-Eigenschaft permissionController
der HealthConnectClient
-Schnittstelle verwenden, um Berechtigungen zu prüfen. Das geschieht in der Regel vor jedem Anruf beim Kunden.
Um diese Funktion zu testen, können Sie mit FakePermissionController
festlegen, welche Berechtigungen verfügbar sind:
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 sehr häufige Fehlerquelle. FakeHealthConnectClient
bietet daher Mechanismen, mit denen Sie überprüfen können, ob Ihre Paginierungsimplementierung für Datensätze und Änderungen korrekt funktioniert.
Das zu testende Subjekt, in unserem Beispiel HealthConnectManager
, kann die Seitengröße in ReadRecordsRequest
angeben:
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 testen. Sie können beispielsweise fünf Datensätze einfügen, sodass 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 gefälschten Daten, aber Sie können die von der Bibliothek verwendeten Daten und Generatoren in Android Code Search verwenden.
Wenn Sie Metadatenwerte in Tests simulieren möchten, können Sie MetadataTestHelper
verwenden. Dadurch wird die Erweiterungsfunktion populatedWithTestValues()
bereitgestellt, mit der simuliert wird, wie Health Connect Metadatenwerte beim Einfügen von Datensätzen einfügt.
Stubs
Mit der overrides
-Eigenschaft von FakeHealthConnectClient
können Sie beliebige Funktionen programmieren (oder ausblenden), sodass beim Aufrufen Ausnahmen ausgelöst werden.
Bei Aggregationsaufrufen können auch beliebige Daten zurückgegeben werden und es wird das Einreihen mehrerer Antworten unterstützt. 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. In der Dokumentation der einzelnen Funktionen finden Sie Informationen dazu, welche Ausnahmen Sie prüfen sollten.
- Prüfen Sie, ob jedem Aufruf, den Sie an den Client senden, die entsprechende Berechtigungsprüfung vorangestellt ist.
- Überprüfen Sie die Implementierung der Paginierung.
- Prüfen Sie, was passiert, wenn Sie mehrere Seiten abrufen, aber für eine Seite ein abgelaufenes Token vorhanden ist.