Thư viện Thử nghiệm Health Connect (androidx.health.connect:connect-testing
)
giúp đơn giản hoá việc tạo các chương trình kiểm thử tự động. Bạn có thể dùng thư viện này để xác minh
hành vi của ứng dụng và xác thực rằng ứng dụng phản hồi chính xác với
các trường hợp không phổ biến, khó kiểm tra theo cách thủ công.
Bạn có thể dùng thư viện này để tạo các chương trình kiểm thử đơn vị cục bộ. Các chương trình này thường xác minh hành vi của các lớp trong ứng dụng tương tác với Health Connect khách hàng của bạn.
Để bắt đầu sử dụng thư viện, hãy thêm thư viện này làm phần phụ thuộc kiểm thử:
testImplementation("androidx.health.connect:connect-testing:1.0.0-alpha01")
Điểm truy cập vào thư viện là lớp FakeHealthConnectClient
mà bạn
sử dụng trong kiểm thử để thay thế HealthConnectClient
. FakeHealthConnectClient
có những tính năng sau:
- Một mô hình đại diện cho các bản ghi trong bộ nhớ để bạn có thể chèn, xoá, xoá và đọc tin nhắn
- Tạo mã thông báo thay đổi và theo dõi thay đổi
- Phân trang cho các bản ghi và thay đổi
- Phản hồi tổng hợp được hỗ trợ với các mã giả lập
- Cho phép mọi hàm gửi ngoại lệ
- Có thể dùng
FakePermissionController
để mô phỏng hoạt động kiểm tra quyền
Để tìm hiểu thêm về cách thay thế các phần phụ thuộc trong kiểm thử, hãy đọc Chèn phần phụ thuộc trong Android. Để biết thêm về hàng giả, hãy đọc Sử dụng đối tượng kiểm thử trong Android.
Ví dụ: nếu lớp tương tác với ứng dụng được gọi
HealthConnectManager
và lấy HealthConnectClient
làm phần phụ thuộc
sẽ có dạng như sau:
class HealthConnectManager(
private val healthConnectClient: HealthConnectClient,
...
) { }
Trong kiểm thử, bạn có thể truyền một lớp giả đến lớp đang được kiểm thử:
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)
}
}
Kiểm thử này xác minh rằng hàm fetchReport
giả định trong
HealthConnectManager
lọc chính xác các bản ghi theo hoạt động.
Xác minh ngoại lệ
Hầu hết mọi lệnh gọi đến HealthConnectClient
đều có thể gửi ngoại lệ. Ví dụ:
tài liệu cho insertRecords
đề cập đến các trường hợp ngoại lệ sau:
@throws android.os.RemoteException
cho mọi sự cố truyền tải IPC.@throws SecurityException
cho các yêu cầu có quyền truy cập không được phép.@throws java.io.IOException
đối với mọi sự cố I/O ổ đĩa.
Những ngoại lệ này bao gồm các trường hợp như kết nối kém hoặc không còn khoảng trống trên thiết bị. Ứng dụng của bạn phải phản ứng chính xác với các vấn đề này trong thời gian chạy, vì chúng có thể xảy ra bất cứ lúc nà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)
}
Tổng hợp
Các lệnh gọi tổng hợp không có cách triển khai giả mạo. Thay vào đó, các lệnh gọi tổng hợp
sử dụng các mã giả lập mà bạn có thể lập trình để hoạt động theo một cách nhất định. Bạn có thể truy cập vào
các mã giả lập thông qua thuộc tính overrides
của FakeHealthConnectClient
.
Ví dụ: bạn có thể lập trình hàm tổng hợp để trả về một kết quả cụ thể:
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)
Sau đó, bạn có thể xác minh rằng lớp của bạn đang được kiểm thử, HealthConnectManager
trong
trường hợp, đã xử lý kết quả một cách chính xác:
// 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)
Quyền
Thư viện kiểm thử bao gồm một FakePermissionController
(có thể được truyền)
làm phần phụ thuộc của FakeHealthConnectClient
.
Đối tượng kiểm thử có thể sử dụng PermissionController—through
thuộc tính permissionController
của giao diện HealthConnectClient
– để kiểm tra
để được cấp quyền. Việc này thường được thực hiện trước mỗi lệnh gọi đến ứng dụng.
Để kiểm thử chức năng này, bạn có thể đặt những quyền hiện có bằng cách sử dụng
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)
}
Phân trang
Phân trang là một nguồn lỗi rất phổ biến, vì vậy FakeHealthConnectClient
cung cấp các cơ chế giúp bạn xác minh rằng việc triển khai phân trang cho
các bản ghi và thay đổi hoạt động chính xác.
Đối tượng kiểm thử HealthConnectManager
trong ví dụ của chúng ta có thể chỉ định
kích thước trang trong ReadRecordsRequest
:
fun fetchRecordsReport(pageSize: Int = 1000) }
val pagedRequest =
ReadRecordsRequest(
timeRangeFilter = ...,
recordType = ...,
pageToken = page1.pageToken,
pageSize = pageSize,
)
val page = client.readRecords(pagedRequest)
...
Đặt kích thước trang ở một giá trị nhỏ, chẳng hạn như 2, cho phép bạn dễ dàng kiểm tra
phân trang. Ví dụ: bạn có thể chèn 5 bản ghi để readRecords
trả về 3
các trang khác nhau:
@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)
}
Kiểm thử dữ liệu
Thư viện này chưa bao gồm các API để tạo dữ liệu giả, nhưng bạn có thể sử dụng dữ liệu và trình tạo mà thư viện sử dụng trong Android Code Search.
Đoạn mã tạm thời
Thuộc tính overrides
của FakeHealthConnectClient
cho phép bạn lập trình (hoặc
tìm ra) bất kỳ hàm nào trong số đó để gửi ngoại lệ khi được gọi.
Các lệnh gọi tổng hợp cũng có thể trả về dữ liệu tuỳ ý và hỗ trợ tính năng thêm vào hàng đợi
nhiều câu trả lời. Hãy xem Stub
và MutableStub
để biết thêm thông tin.
Tóm tắt các trường hợp hiếm gặp
- Xác minh rằng ứng dụng của bạn hoạt động như dự kiến khi ứng dụng gửi ra các ngoại lệ. Hãy xem tài liệu về từng hàm để xác định những trường hợp ngoại lệ mà bạn cần kiểm tra.
- Xác minh rằng mỗi cuộc gọi bạn thực hiện đến khách hàng đều được bắt đầu bằng kiểm tra quyền.
- Xác minh cách triển khai tính năng phân trang.
- Xác minh điều gì xảy ra khi bạn tìm nạp nhiều trang nhưng có một trang đã hết hạn mã thông báo.