헬스 커넥트 테스트 라이브러리 (androidx.health.connect:connect-testing
)
자동화된 테스트의 생성을 간소화합니다 이 라이브러리를 사용하여 애플리케이션의 동작을 확인하고 수동으로 테스트하기 어려운 드문 경우에 올바르게 응답하는지 검증할 수 있습니다.
이 라이브러리를 사용하여 로컬 단위 테스트를 만들 수 있습니다. 일반적으로 Health Connect 클라이언트와 상호작용하는 앱의 클래스 동작을 확인하는 테스트입니다.
라이브러리 사용을 시작하려면 테스트 종속 항목으로 추가합니다.
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)
}
집계
집계 호출에는 허위 구현이 없습니다. 대신
특정 방식으로 동작하도록 프로그래밍할 수 있는 스텁을 사용합니다. 다음에서 액세스할 수 있습니다.
FakeHealthConnectClient
의 overrides
속성을 통해 스텁을 전달합니다.
예를 들어 특정 결과를 반환하도록 집계 함수를 프로그래밍할 수 있습니다.
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)
권한
테스트 라이브러리에는 FakeHealthConnectClient
에 종속 항목으로 전달할 수 있는 FakePermissionController
가 포함되어 있습니다.
테스트 대상은 HealthConnectClient
인터페이스의 PermissionController—through
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 코드 검색의 라이브러리에서 사용되는 데이터 및 생성기를 제공합니다.
스텁
FakeHealthConnectClient
의 overrides
속성을 사용하면
스텁 아웃)하여 함수가 호출될 때 예외를 발생시키도록 합니다.
집계 호출은 임의의 데이터를 반환할 수도 있으며 여러 응답을 큐에 추가하는 것을 지원합니다. 자세한 내용은 Stub
및 MutableStub
를 참고하세요.
특이 사례 요약
- 클라이언트에서 예외가 발생할 때 앱이 예상대로 작동하는지 확인합니다. 각 함수의 문서를 확인하여 확인해야 하는 예외를 파악합니다.
- 클라이언트에 대한 모든 호출 앞에 올바른 권한을 검사할 수 있습니다.
- 페이지로 나누기 구현을 확인합니다.
- 여러 페이지를 가져왔는데 한 페이지가 만료된 경우 어떻게 되는지 확인하기 토큰입니다.