Tạo các bài kiểm thử đơn vị bằng thư viện Kiểm thử Health Connect

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 StubMutableStub để 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.