สร้างการทดสอบ 1 หน่วยโดยใช้ไลบรารีการทดสอบ Health Connect

ไลบรารีการทดสอบ Health Connect (androidx.health.connect:connect-testing) ลดความซับซ้อนในการสร้างการทดสอบอัตโนมัติ คุณใช้ไลบรารีนี้เพื่อยืนยันได้ การทำงานของแอปพลิเคชันของคุณ และตรวจสอบว่าแอปพลิเคชันตอบสนองอย่างถูกต้อง กรณีที่พบได้น้อย ซึ่งทดสอบด้วยตนเองได้ยาก

คุณสามารถใช้ไลบรารีเพื่อสร้างการทดสอบหน่วยในเครื่อง ซึ่งโดยทั่วไปจะยืนยัน พฤติกรรมของชั้นเรียนในแอปที่โต้ตอบกับ Health Connect

หากต้องการเริ่มใช้ไลบรารี ให้เพิ่มไลบรารีดังกล่าวเป็นทรัพยากร Dependency ทดสอบ ดังนี้

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

จุดแรกเข้าของห้องสมุดคือชั้นเรียน FakeHealthConnectClient ซึ่งคุณ ใช้ในการทดสอบเพื่อแทนที่ HealthConnectClient FakeHealthConnectClient มีฟีเจอร์ดังต่อไปนี้

  • การแสดงระเบียนในหน่วยความจำ เพื่อให้คุณสามารถแทรก นำออก ลบ และ อ่าน
  • การสร้างโทเค็นการเปลี่ยนแปลงและการติดตามการเปลี่ยนแปลง
  • การใส่เลขหน้าสำหรับบันทึกและการเปลี่ยนแปลง
  • ระบบรองรับคำตอบการรวมด้วยต้นขั้ว
  • อนุญาตให้ทุกฟังก์ชันส่งข้อยกเว้น
  • FakePermissionController ที่สามารถใช้เพื่อจำลองการตรวจสอบสิทธิ์

หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับการแทนที่ทรัพยากร Dependency ในการทดสอบ โปรดอ่าน การแทรกทรัพยากร Dependency ใน Android หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับของปลอม โปรดอ่าน การใช้เลขคู่ทดสอบใน Android

เช่น ถ้าเรียกใช้คลาสที่โต้ตอบกับไคลเอ็นต์ HealthConnectManager และต้องใช้ HealthConnectClient เป็นทรัพยากร Dependency จะมีลักษณะดังนี้

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

การรวม

การเรียกการรวมไม่มีการติดตั้งใช้งานปลอม แต่การเรียกการรวมข้อมูล ใช้ต้นขั้วที่คุณสามารถตั้งโปรแกรมให้ทำงานในลักษณะต่างๆ ได้ คุณสามารถเข้าถึง ต้นขั้วผ่านพร็อพเพอร์ตี้ overrides ของ FakeHealthConnectClient

ตัวอย่างเช่น คุณตั้งโปรแกรมฟังก์ชันการรวมให้แสดงผลการค้นหาที่เฉพาะเจาะจงได้ ดังนี้

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 ซึ่งสามารถส่งผ่าน เป็นทรัพยากร Dependency ของ FakeHealthConnectClient

วัตถุของคุณที่อยู่ภายใต้การทดสอบสามารถใช้PermissionController—through พร็อพเพอร์ตี้ permissionController ของอินเทอร์เฟซ HealthConnectClient เพื่อตรวจสอบ เพื่อขอสิทธิ์ ซึ่งโดยปกติจะดำเนินการก่อนการโทรติดต่อลูกค้าทุกครั้ง

หากต้องการทดสอบฟังก์ชันการทำงานนี้ คุณสามารถตั้งค่าสิทธิ์ที่ใช้ได้โดยใช้ 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 จะช่วยให้คุณทดสอบได้อย่างง่ายดาย การใส่เลขหน้า เช่น คุณสามารถแทรกระเบียน 5 รายการเพื่อให้ readRecords แสดงผล 3 หน้าต่างๆ ได้แก่

@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 Code Search

ต้นกำเนิด

พร็อพเพอร์ตี้ overrides ของ FakeHealthConnectClient ช่วยให้คุณเขียนโปรแกรมได้ (หรือ stub out) ฟังก์ชันใดๆ ของฟังก์ชันนั้นเพื่อให้ระบบแสดงข้อยกเว้นเมื่อเรียกใช้ นอกจากนี้ การเรียกใช้การรวมยังแสดงข้อมูลที่กําหนดเองได้ และรองรับการจัดคิว คำตอบที่หลากหลาย ดูข้อมูลเพิ่มเติมได้ที่ Stub และ MutableStub

สรุปกรณีที่เป็นปัญหาที่สุด

  • ตรวจสอบว่าแอปทำงานตามที่คาดไว้เมื่อลูกค้าส่งข้อยกเว้น โปรดดูเอกสารของแต่ละฟังก์ชันเพื่อดูว่ามีข้อยกเว้นอะไรบ้าง ควรตรวจสอบ
  • ยืนยันว่าทุกการโทรที่คุณเรียกหาลูกค้ามีการกำหนดเป็น ตรวจสอบสิทธิ์
  • ยืนยันการใช้การใส่เลขหน้า
  • ตรวจสอบว่าเกิดอะไรขึ้นเมื่อคุณดึงข้อมูลหน้าเว็บหลายหน้าแต่มีหน้าหนึ่งหมดอายุแล้ว โทเค็น