헬스 커넥트 테스트 라이브러리를 사용하여 단위 테스트 만들기

헬스 커넥트 테스트 라이브러리 (androidx.health.connect:connect-testing) 자동화된 테스트 생성을 간소화합니다 이 라이브러리를 사용하여 애플리케이션의 동작을 확인하고 이에 올바르게 응답하는지 드물지만 이러한 경우는 수동으로 테스트하기 어렵습니다.

이 라이브러리를 사용하여 일반적으로 다음을 확인하는 로컬 단위 테스트를 만들 수 있습니다. 헬스 커넥트와 상호작용하는 앱의 클래스 동작 클라이언트와 동일합니다.

라이브러리 사용을 시작하려면 테스트 종속 항목으로 추가합니다.

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

라이브러리의 진입점은 FakeHealthConnectClient 클래스이며 HealthConnectClient를 대체하는 테스트에서 사용합니다. FakeHealthConnectClient 에는 다음과 같은 기능이 있습니다.

  • 데이터를 삽입, 제거, 삭제 및 삭제할 수 있는 메모리 내 표현 읽기
  • 변경 토큰 및 변경 추적 생성
  • 기록 및 변경사항 페이지로 나누기
  • 집계 응답은 스텁으로 지원됨
  • 모든 함수에서 예외를 발생시키도록 허용
  • 권한 확인을 에뮬레이션하는 데 사용할 수 있는 FakePermissionController

테스트에서 종속 항목을 바꾸는 방법을 자세히 알아보려면 다음을 참고하세요. Android의 종속 항목 삽입 가짜 제품에 관해 자세히 알아보려면 다음을 참고하세요. Android에서 테스트 더블 사용.

예를 들어 클라이언트와 상호작용하는 클래스가 HealthConnectManager를 사용하고 HealthConnectClient를 종속 항목으로 사용하면 다음과 같습니다.

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

테스트에서는 테스트 중인 클래스에 모조 구현을 대신 전달할 수 있습니다.

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

이 테스트는 다음 위치에서 가상 fetchReport 함수가 HealthConnectManager에서는 활동별로 레코드를 적절하게 필터링합니다.

예외 확인

거의 모든 HealthConnectClient 호출이 예외를 발생시킬 수 있습니다. 예를 들어 insertRecords에 관한 문서에 다음 예외가 언급되어 있습니다.

  • @throws android.os.RemoteException: 모든 IPC 전송 오류
  • @throws SecurityException: 허용되지 않은 액세스가 포함된 요청의 경우
  • @throws java.io.IOException: 모든 디스크 I/O 문제

이러한 예외는 연결 상태가 좋지 않거나 기기에 남은 공간이 없는 등의 경우에 적용됩니다. 있습니다. 앱이 이러한 런타임 문제에 올바르게 대응해야 합니다. 발생할 수 있습니다

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

집계

집계 호출에는 허위 구현이 없습니다. 대신 특정 방식으로 동작하도록 프로그래밍할 수 있는 스텁을 사용합니다. 다음에서 액세스할 수 있습니다. FakeHealthConnectClientoverrides 속성을 통해 스텁을 전달합니다.

예를 들어 특정 결과를 반환하도록 집계 함수를 프로그래밍할 수 있습니다.

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)

그런 다음 테스트 중인 클래스(HealthConnectManager)를 확인할 수 있습니다. 결과를 올바르게 처리했습니다.

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

권한

테스트 라이브러리에는 통과할 수 있는 FakePermissionController가 포함되어 있습니다. FakeHealthConnectClient의 종속 항목으로 제공됩니다.

테스트 대상은 PermissionController—through HealthConnectClient 인터페이스의 permissionController 속성 - 확인 대상 확인하세요. 이 작업은 일반적으로 클라이언트를 호출할 때마다 실행됩니다.

이 기능을 테스트하려면 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)
}

페이지 매김

페이지로 나누기는 버그의 매우 일반적인 원인이므로 FakeHealthConnectClient 이 API에 대한 Paging 구현이 올바르게 동작합니다.

테스트 대상(이 예의 HealthConnectManager)은 ReadRecordsRequest의 페이지 크기:

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

페이지 크기를 2와 같이 작은 값으로 설정하면 페이지로 나누기 예를 들어 readRecords가 3을 반환하도록 레코드 5개를 삽입할 수 있습니다. 다른 페이지:

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

테스트 데이터

라이브러리에는 아직 가짜 데이터를 생성하는 API가 포함되어 있지 않지만 Android 코드 검색의 라이브러리에서 사용하는 데이터 및 생성기를 제공합니다.

스텁

FakeHealthConnectClientoverrides 속성을 사용하면 스텁 아웃)하여 함수가 호출될 때 예외를 발생시키도록 합니다. 집계 호출은 임의의 데이터를 반환할 수도 있으며 큐에 추가하는 기능을 지원합니다. 여러 응답을 반환할 수 있습니다. 자세한 내용은 StubMutableStub를 참고하세요.

특이 사례 요약

  • 클라이언트가 예외를 발생시킬 때 앱이 예상대로 작동하는지 확인합니다. 각 함수의 문서를 확인하여 예외에 해당하는지 확인하세요. 확인해야 합니다
  • 클라이언트에 대한 모든 호출 앞에 올바른 권한을 검사할 수 있습니다.
  • 페이지로 나누기 구현을 확인합니다.
  • 여러 페이지를 가져왔는데 한 페이지가 만료된 경우 어떻게 되는지 확인하기 토큰입니다.