Biblioteka testów Health Connect (androidx.health.connect:connect-testing
)
upraszcza tworzenie testów zautomatyzowanych. Możesz użyć tej biblioteki, aby sprawdzić zachowanie aplikacji i sprawdzić, czy reaguje ona prawidłowo w nietypowych przypadkach, które trudno jest przetestować ręcznie.
Możesz jej używać do tworzenia lokalnych testów jednostkowych, które zwykle sprawdzają zachowanie zajęć w aplikacji, które współdziałają z 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żna wstawiać, usuwać, usuwać przeczytaj je
- Generowanie tokenów zmian i śledzenie zmian
- Podział na strony rekordów i zmian
- Odpowiedzi agregacji są obsługiwane za pomocą szablonów
- Zezwala dowolnej funkcji na zgłaszanie wyjątków
- Interfejs
FakePermissionController
, który może być używany do emulacji 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 podróbkach znajdziesz w artykule Korzystanie z podwójnych testów na Androidzie.
Jeśli na przykład klasa, która wchodzi w interakcję z klientem, ma nazwę HealthConnectManager
i zależność HealthConnectClient
, będzie wyglądać tak:
class HealthConnectManager(
private val healthConnectClient: HealthConnectClient,
...
) { }
Podczas testów możesz przekazać fałszywy obiekt do testowanej klasy:
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 funkcji HealthConnectManager
prawidłowo filtruje rekordy według aktywności.
Weryfikuję wyjątki
Prawie każde wywołanie funkcji HealthConnectClient
może zgłosić wyjątki. Przykład:
w dokumentacji dotyczącej domeny insertRecords
wymieniono te wyjątki:
@throws android.os.RemoteException
w przypadku awarii transportu IPC.@throws SecurityException
w przypadku żądań z niedozwolonym dostępem.@throws java.io.IOException
w przypadku problemów z I/O dysku.
Te wyjątki dotyczą takich sytuacji, jak słabe połączenie lub brak miejsca na urządzenia. Twoja aplikacja musi prawidłowo reagować na te problemy w czasie działania aplikacji, mogą wystąpić w każdej chwili.
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 agregujące nie zawierają fałszywych implementacji. Zamiast tego wywołania agregacji
używać wycinków, które możesz zaprogramować, aby działały w określony sposób. Dostęp do skrótów masz w ramach właściwości overrides
usługi FakeHealthConnectClient
.
Na przykład funkcję agregacji można zaprogramować w taki sposób, 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 testowane zajęcia, HealthConnectManager
, na
udało się przetworzyć wynik prawidłowo:
// 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 zasób FakePermissionController
, który można przekazać
jako zależność do FakeHealthConnectClient
.
Osoba badana może sprawdzić uprawnienia za pomocą właściwości PermissionController—through
w usługach permissionController
i HealthConnectClient
w interfejsie HealthConnectClient
. Zwykle odbywa się to przed każdym wywołaniem klienta.
Aby przetestować tę funkcję, możesz ustawić dostępne uprawnienia 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
zapewnia mechanizmy, które ułatwiają sprawdzanie, czy implementacja stronowania dla rekordów i zmian działa prawidłowo.
Testowany użytkownik, w naszym przykładzie HealthConnectManager
, może określić rozmiar strony w elementach ReadRecordsRequest
:
fun fetchRecordsReport(pageSize: Int = 1000) }
val pagedRequest =
ReadRecordsRequest(
timeRangeFilter = ...,
recordType = ...,
pageToken = page1.pageToken,
pageSize = pageSize,
)
val page = client.readRecords(pagedRequest)
...
Ustawienie małego rozmiaru strony, np. 2, pozwala łatwo przetestować strony powiązane. Możesz np. 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 generowania używanych przez nią w Android Code Search.
Stubs
Właściwość overrides
obiektu FakeHealthConnectClient
umożliwia programowanie (lub zastępowanie) dowolnej z jego funkcji, tak aby wyrzucały wyjątki po wywołaniu.
Wywołania agregacji również mogą zwracać dowolne dane i obsługują kolejkowanie
wiele odpowiedzi. Więcej informacji znajdziesz w sekcjach Stub
i MutableStub
.
Podsumowanie przypadków skrajnych
- Sprawdź, czy aplikacja działa zgodnie z oczekiwaniami, gdy klient zgłasza wyjątki. Aby dowiedzieć się, jakie wyjątki należy sprawdzić, zapoznaj się z dokumentacją poszczególnych funkcji.
- Sprawdź, czy każde połączenie z klientem jest poprzedzone odpowiednim sprawdzić uprawnienia.
- Sprawdź implementację strony z przewijaniem.
- Sprawdź, co się dzieje w przypadku pobrania wielu stron, ale jedna z nich straciła ważność token.