Biblioteka testowa Health Connect (androidx.health.connect:connect-testing
) ułatwia tworzenie testów automatycznych. Możesz użyć tej biblioteki, aby sprawdzić działanie aplikacji i potwierdzić, że prawidłowo reaguje ona na nietypowe przypadki, które trudno jest przetestować ręcznie.
Za pomocą tej biblioteki możesz tworzyć lokalne testy jednostkowe, które zwykle weryfikują działanie klas w aplikacji, które wchodzą w interakcję z klientem Health Connect.
Aby zacząć korzystać z biblioteki, dodaj ją jako zależność testową:
testImplementation("androidx.health.connect:connect-testing:1.0.0-alpha01")
Punktem wejścia do biblioteki jest klasa FakeHealthConnectClient
, której używasz w testach do zastąpienia klasy HealthConnectClient
. FakeHealthConnectClient
ma te funkcje:
- Reprezentacja rekordów w pamięci, dzięki czemu możesz je wstawiać, usuwać i odczytywać.
- Generowanie tokenów zmian i śledzenie zmian
- Podział na strony dotyczący rekordów i zmian
- Odpowiedzi agregacji są obsługiwane w przypadku elementów zastępczych
- Zezwala na zgłaszanie wyjątków przez dowolną funkcję
FakePermissionController
, którego można użyć do emulowania sprawdzania uprawnień.
Więcej informacji o zastępowaniu zależności w testach znajdziesz w artykule Wstrzykiwanie zależności w Androidzie. Więcej informacji o obiektach zastępczych znajdziesz w artykule Używanie obiektów zastępczych w Androidzie.
Jeśli na przykład klasa, która wchodzi w interakcję z klientem, ma nazwę HealthConnectManager
i jako zależność przyjmuje HealthConnectClient
, będzie wyglądać tak:
class HealthConnectManager(
private val healthConnectClient: HealthConnectClient,
...
) { }
W testach możesz zamiast tego przekazać do testowanej klasy obiekt zastępczy:
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)
}
}
Ten test sprawdza, czy fikcyjna funkcja fetchReport
w HealthConnectManager
prawidłowo filtruje rekordy według aktywności.
Weryfikowanie wyjątków
Prawie każde wywołanie funkcji HealthConnectClient
może zgłosić wyjątek. Na przykład dokumentacja insertRecords
zawiera te wyjątki:
@throws android.os.RemoteException
w przypadku niepowodzeń związanych z transportem IPC.@throws SecurityException
w przypadku próśb z nieautoryzowanym dostępem.@throws java.io.IOException
w przypadku problemów z operacjami wejścia/wyjścia dysku.
Wyjątki te obejmują przypadki takie jak słabe połączenie lub brak miejsca na urządzeniu. Aplikacja musi prawidłowo reagować na te problemy w czasie działania, ponieważ mogą one wystąpić w dowolnym momencie.
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)
}
Agregacja
Wywołania agregacji nie mają fałszywych implementacji. Zamiast tego wywołania agregacji
używają stubów, które możesz zaprogramować tak, aby zachowywały się w określony sposób. Dostęp do elementów zastępczych możesz uzyskać za pomocą właściwości overrides
obiektu FakeHealthConnectClient
.
Możesz na przykład zaprogramować funkcję agregującą tak, aby zwracała określony wynik:
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)
Następnie możesz sprawdzić, czy testowana klasa, w tym przypadku HealthConnectManager
, prawidłowo przetworzyła wynik:
// 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)
Uprawnienia
Biblioteka testowa zawiera element FakePermissionController
, który można przekazać jako zależność do elementu FakeHealthConnectClient
.
Osoba testująca może użyć właściwości PermissionController—through
permissionController
interfejsu HealthConnectClient
, aby sprawdzić uprawnienia. Zwykle odbywa się to przed każdym wywołaniem klienta.
Aby przetestować tę funkcję, możesz ustawić, które uprawnienia są dostępne, za pomocą 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)
}
Podział na strony
Stronicowanie jest bardzo częstym źródłem błędów, dlatego FakeHealthConnectClient
udostępnia mechanizmy, które pomagają sprawdzić, czy implementacja stronicowania rekordów i zmian działa prawidłowo.
Testowany obiekt, w naszym przykładzie HealthConnectManager
, może określić rozmiar strony w ReadRecordsRequest
:
fun fetchRecordsReport(pageSize: Int = 1000) }
val pagedRequest =
ReadRecordsRequest(
timeRangeFilter = ...,
recordType = ...,
pageToken = page1.pageToken,
pageSize = pageSize,
)
val page = client.readRecords(pagedRequest)
...
Ustawienie małej wartości rozmiaru strony, np. 2, umożliwia testowanie paginacji. Możesz na przykład wstawić 5 rekordów, aby funkcja readRecords
zwracała 3 różne strony:
@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)
}
Dane testowe
Biblioteka nie zawiera jeszcze interfejsów API do generowania fałszywych danych, ale możesz używać danych i generatorów używanych przez bibliotekę w Android Code Search.
Aby w testach symulować wartości metadanych, możesz użyć MetadataTestHelper
. Zapewnia to funkcję rozszerzenia
populatedWithTestValues()
, która symuluje wypełnianie wartości metadanych przez Health Connect podczas wstawiania rekordu.
Stubs
Właściwość overrides
obiektu FakeHealthConnectClient
umożliwia zaprogramowanie (lub zaimplementowanie) dowolnej z jego funkcji tak, aby w momencie wywołania zgłaszały wyjątki.
Wywołania agregacji mogą też zwracać dowolne dane i obsługują kolejkowanie wielu odpowiedzi. Więcej informacji znajdziesz w sekcjach Stub
i MutableStub
.
Podsumowanie przypadków brzegowych
- Sprawdź, czy aplikacja działa zgodnie z oczekiwaniami, gdy klient zgłasza wyjątki. Zapoznaj się z dokumentacją każdej funkcji, aby dowiedzieć się, jakie wyjątki należy sprawdzić.
- Sprawdź, czy każde wywołanie klienta jest poprzedzone odpowiednim sprawdzeniem uprawnień.
- Sprawdź implementację paginacji.
- Sprawdź, co się stanie, gdy pobierzesz wiele stron, ale jedna z nich ma wygasły token.