Creare test delle unità utilizzando la libreria dei test di Connessione Salute

La libreria dei test di Connessione Salute (androidx.health.connect:connect-testing) semplifica la creazione di test automatici. Puoi usare questa libreria per verificare il comportamento dell'applicazione e verificare che risponda correttamente e rari, difficili da testare manualmente.

Puoi utilizzare la libreria per creare test delle unità locali, che in genere verificano il comportamento dei corsi nella tua app che interagiscono con Connessione Salute di destinazione.

Per iniziare a utilizzare la libreria, aggiungila come dipendenza di test:

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

Il punto di accesso alla libreria è la classe FakeHealthConnectClient, che puoi usare nei test per sostituire HealthConnectClient. FakeHealthConnectClient include le seguenti funzionalità:

  • Una rappresentazione in memoria dei record, che consente di inserire, rimuovere, eliminare leggili
  • Generazione di token di modifica e monitoraggio delle modifiche
  • Impaginazione per record e modifiche
  • Le risposte di aggregazione sono supportate con stub
  • Consente a qualsiasi funzione di generare eccezioni
  • Un elemento FakePermissionController che può essere utilizzato per emulare i controlli delle autorizzazioni

Per scoprire di più sulla sostituzione delle dipendenze nei test, consulta Iniezione di dipendenze in Android. Per saperne di più sui falsi, leggi Utilizzo del test del doppio in Android.

Ad esempio, se la classe che interagisce con il client viene chiamata HealthConnectManager e richiede HealthConnectClient come dipendenza, sarebbe:

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

Nei test, puoi passare un falso al corso sottoposto a test:

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

Questo test verifica che l'elemento fetchReport fittizio funziona in HealthConnectManager filtra correttamente i record per attività.

Verifica delle eccezioni

Quasi tutte le chiamate a HealthConnectClient possono generare eccezioni. Ad esempio: la documentazione di insertRecords menziona queste eccezioni:

  • @throws android.os.RemoteException per eventuali errori di trasporto IPC.
  • @throws SecurityException per le richieste con accesso non consentito.
  • @throws java.io.IOException per eventuali problemi di I/O del disco.

Queste eccezioni riguardano casi quali problemi di connessione o mancanza di spazio sulla dispositivo. La tua app deve reagire correttamente a questi problemi di runtime, avvengono in qualsiasi momento.

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

Aggregazione

Le chiamate di aggregazione non hanno implementazioni false. L'aggregazione chiama invece usare stub che puoi programmare in modo che comportino in un certo modo. Puoi accedere ai stub tramite la proprietà overrides di FakeHealthConnectClient.

Ad esempio, puoi programmare la funzione aggregata in modo che restituisca un risultato specifico:

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)

Dopodiché puoi verificare che il corso oggetto di test, HealthConnectManager in questo ha elaborato correttamente il risultato:

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

Autorizzazioni

La libreria di test include un valore FakePermissionController, che può essere superato come dipendenza a FakeHealthConnectClient.

Il soggetto sottoposto a test può utilizzare PermissionController—through permissionController dell'interfaccia HealthConnectClient: da verificare per le autorizzazioni. In genere questa operazione viene eseguita prima di ogni chiamata al cliente.

Per testare questa funzionalità, puoi impostare le autorizzazioni disponibili utilizzando 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)
}

Impaginazione

L'impaginazione è una fonte di bug molto comune, per cui FakeHealthConnectClient fornisce meccanismi per aiutarti a verificare che l'implementazione del paging per il comportamento dei record e delle modifiche.

Il soggetto oggetto del test, HealthConnectManager nel nostro esempio, può specificare dimensioni pagina in ReadRecordsRequest:

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

L'impostazione di un valore basso per le dimensioni della pagina, come 2, consente di testare l'impaginazione. Ad esempio, puoi inserire 5 record in modo che readRecords restituisca 3 pagine diverse:

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

Dati del test

La libreria non include ancora API per generare dati falsi, ma puoi utilizzare i dati e i generatori utilizzati dalla libreria in Ricerca Codice Android.

Stub

La proprietà overrides di FakeHealthConnectClient ti consente di programmare (oppure chiudere) tutte le sue funzioni in modo da generare eccezioni quando vengono chiamate. Le chiamate di aggregazione possono anche restituire dati arbitrari e supporta l'accodamento più risposte. Per saperne di più, vedi Stub e MutableStub.

Riepilogo dei casi limite

  • Verifica che l'app si comporti come previsto quando il client genera eccezioni. Controlla la documentazione di ciascuna funzione per capire quali eccezioni dovrebbe controllare.
  • Verifica che ogni chiamata che effettui al cliente sia preceduta dal carattere controllo delle autorizzazioni.
  • Verifica l'implementazione dell'impaginazione.
  • Verifica cosa succede quando recuperi più pagine ma una è scaduta di accesso.