تسهّل مكتبة Health Connect Testing (الإصدار 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
في حال حدوث أي أعطال في نقل البيانات بين العمليات.-
@throws SecurityException
للطلبات التي تتضمّن أذونات وصول غير مسموح بها @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)
}
التجميع
لا تتضمّن طلبات التجميع عمليات تنفيذ زائفة. بدلاً من ذلك، تستخدم طلبات التجميع رموزًا بديلة يمكنك برمجتها لتتصرّف بطريقة معيّنة. يمكنك الوصول إلى
النماذج الأولية من خلال السمة 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
، والتي يمكن تمريرها
كعنصر تابع إلى FakeHealthConnectClient
.
يمكن أن يستخدم الموضوع الخاضع للاختبار السمة PermissionController—through
في واجهة HealthConnectClient
للتحقّق من الأذونات.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، باختبار تقسيم الصفحات. على سبيل المثال، يمكنك إدراج 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)
}
بيانات الاختبار
لا تتضمّن المكتبة واجهات برمجة تطبيقات لإنشاء بيانات وهمية حتى الآن، ولكن يمكنك استخدام البيانات والمولّدات التي تستخدمها المكتبة في بحث رموز Android.
لمحاكاة قيم بيانات التعريف في الاختبارات، يمكنك استخدام
MetadataTestHelper
. يوفّر ذلك دالة الإضافة
populatedWithTestValues()
التي تحاكي عملية ملء Health Connect لقيم البيانات الوصفية أثناء إدراج السجلّ.
القصاصات
تتيح لك السمة overrides
الخاصة بالكائن FakeHealthConnectClient
برمجة (أو
إنشاء نسخة تجريبية) أي من وظائفه بحيث تعرض استثناءات عند استدعائها.
يمكن أن تعرض طلبات التجميع أيضًا بيانات عشوائية، كما تتيح وضع ردود متعددة في قائمة الانتظار. يمكنك الاطّلاع على Stub
وMutableStub
لمزيد من المعلومات.
ملخّص الحالات الهامشية
- تأكَّد من أنّ تطبيقك يتصرّف على النحو المتوقّع عندما يطرح العميل استثناءات. راجِع مستندات كل دالة لمعرفة الاستثناءات التي يجب التحقّق منها.
- تأكَّد من أنّ كل طلب ترسله إلى العميل يسبقه التحقّق من الأذونات المناسبة.
- تأكَّد من صحة عملية تنفيذ الترقيم.
- تحقَّق من الإجراءات التي تحدث عند جلب صفحات متعددة ولكن إحداها تتضمّن رمزًا مميزًا منتهي الصلاحية.