헬스 커넥트 테스트 라이브러리 (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)
}
}
이 테스트는 HealthConnectManager
의 가상 fetchReport
함수가 활동별로 레코드를 올바르게 필터링하는지 확인합니다.
예외 확인
HealthConnectClient
에 대한 거의 모든 호출은 예외를 발생시킬 수 있습니다. 예를 들어 insertRecords
문서에는 다음과 같은 예외가 언급되어 있습니다.
- IPC 전송 실패의 경우
@throws android.os.RemoteException
@throws SecurityException
: 허용되지 않은 액세스 권한이 있는 요청의 경우- 디스크 I/O 문제의 경우
@throws java.io.IOException
이러한 예외는 연결 불량 또는 기기에 남은 공간이 없는 경우와 같은 사례를 포함합니다. 이러한 런타임 문제는 언제든지 발생할 수 있으므로 앱이 올바르게 대응해야 합니다.
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)
권한
테스트 라이브러리에는 FakePermissionController
가 포함되어 있으며, 이는 FakeHealthConnectClient
에 종속 항목으로 전달될 수 있습니다.
테스트 대상은 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
에서는 레코드 및 변경사항의 페이지로 나누기 구현이 올바르게 작동하는지 확인할 수 있는 메커니즘을 제공합니다.
테스트 대상인 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 코드 검색에서 라이브러리에서 사용하는 데이터와 생성기를 사용할 수 있습니다.
테스트에서 메타데이터 값을 모의 처리하려면 MetadataTestHelper
를 사용하면 됩니다. 이렇게 하면 레코드 삽입 중에 메타데이터 값을 채우는 Health Connect를 시뮬레이션하는 populatedWithTestValues()
확장 프로그램 함수가 제공됩니다.
스텁
FakeHealthConnectClient
의 overrides
속성을 사용하면 호출 시 예외가 발생하도록 함수를 프로그래밍 (또는 스텁 처리)할 수 있습니다.
집계 호출은 임의의 데이터를 반환할 수도 있으며 여러 응답의 대기열 추가를 지원합니다. 자세한 내용은 Stub
및 MutableStub
을 참고하세요.
예외 사례 요약
- 클라이언트에서 예외를 발생시킬 때 앱이 예상대로 작동하는지 확인합니다. 각 함수의 문서를 확인하여 확인해야 하는 예외를 파악하세요.
- 클라이언트에 대한 모든 호출이 적절한 권한 확인으로 시작되는지 확인합니다.
- 페이지로 나누기 구현을 확인합니다.
- 여러 페이지를 가져오지만 하나에 만료된 토큰이 있는 경우 발생하는 상황을 확인합니다.