الگوهای رایج

می‌توانید برنامه Compose خود را با رویکردها و الگوهای تثبیت‌شده آزمایش کنید.

آزمایش در محیط ایزوله

ComposeTestRule به شما امکان می‌دهد فعالیتی را شروع کنید که هر ترکیب‌پذیری را نمایش می‌دهد: کل برنامه، یک صفحه، یا یک عنصر کوچک. همچنین تمرین خوبی است که بررسی کنید که composables شما به‌درستی کپسوله‌سازی شده‌اند و به‌طور مستقل کار می‌کنند، که این امر امکان آزمایش UI آسان‌تر و متمرکزتر را فراهم می‌کند.

این بدان معنا نیست که شما باید فقط آزمون‌های واحد واسط کاربر ایجاد کنید. آزمایش‌های واسط کاربر که بخش‌های بزرگ‌تری از واسط کاربر را پوشش می‌دهند نیز بسیار مهم هستند.

پس‌از تنظیم محتوای خودتان، به فعالیت و منابع دسترسی پیدا کنید

اغلب اوقات باید محتوای تحت آزمایش را بااستفاده از composeTestRule.setContent تنظیم کنید و همچنین باید به منابع فعالیت دسترسی داشته باشید، برای مثال برای اینکه مطمئن شوید نوشتار نمایش‌داده‌شده با منبع رشته مطابقت دارد. بااین‌حال، اگر فعالیت ازقبل setContent را فراخوانی کرده باشد، نمی‌توانید آن را در قانونی که با createAndroidComposeRule() ایجاد شده است فراخوانی کنید.

الگوی رایج برای دستیابی به این هدف، ایجاد AndroidComposeTestRule بااستفاده از فعالیت خالی مانند ComponentActivity است.

class MyComposeTest {

    @get:Rule
    val composeTestRule = createAndroidComposeRule<ComponentActivity>()

    @Test
    fun myTest() {
        // Start the app
        composeTestRule.setContent {
            MyAppTheme {
                MainScreen(uiState = exampleUiState, /*...*/)
            }
        }
        val continueLabel = composeTestRule.activity.getString(R.string.next)
        composeTestRule.onNodeWithText(continueLabel).performClick()
    }
}

توجه داشته باشید که ComponentActivity باید به فایل AndroidManifest.xml برنامه‌تان اضافه شود. با افزودن این وابستگی به ماژول خود، آن را فعال کنید:

debugImplementation("androidx.compose.ui:ui-test-manifest:$compose_version")

ویژگی‌های معنایی سفارشی

می‌توانید ویژگی‌های معنایی سفارشی ایجاد کنید تا اطلاعات را برای آزمایش‌ها آشکار کنید. برای انجام این کار، SemanticsPropertyKey جدیدی تعریف کنید و آن را بااستفاده از SemanticsPropertyReceiver دردسترس قرار دهید.

// Creates a semantics property of type Long.
val PickedDateKey = SemanticsPropertyKey<Long>("PickedDate")
var SemanticsPropertyReceiver.pickedDate by PickedDateKey

اکنون از آن ویژگی در اصلاح‌کننده semantics استفاده کنید:

val datePickerValue by remember { mutableStateOf(0L) }
MyCustomDatePicker(
    modifier = Modifier.semantics { pickedDate = datePickerValue }
)

از آزمایش‌ها، از SemanticsMatcher.expectValue برای تأیید مقدار ویژگی استفاده کنید:

composeTestRule
    .onNode(SemanticsMatcher.expectValue(PickedDateKey, 1445378400)) // 2015-10-21
    .assertExists()

درستی‌سنجی بازیابی وضعیت

مطمئن شوید که وضعیت عناصر Compose شما به‌درستی بازیابی می‌شود وقتی که فعالیت یا فرایند دوباره ایجاد می‌شود. چنین بررسی‌هایی را بدون تکیه بر بازسازی فعالیت با کلاس StateRestorationTester انجام دهید.

این کلاس به شما امکان می‌دهد بازسازی یک ترکیب‌پذیر را شبیه‌سازی کنید. این ابزار به‌ویژه برای درستی‌سنجی کردن پیاده‌سازی rememberSaveable مفید است.


class MyStateRestorationTests {

    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun onRecreation_stateIsRestored() {
        val restorationTester = StateRestorationTester(composeTestRule)

        restorationTester.setContent { MainScreen() }

        // TODO: Run actions that modify the state

        // Trigger a recreation
        restorationTester.emulateSavedInstanceStateRestore()

        // TODO: Verify that state has been correctly restored.
    }
}

آزمایش پیکربندی‌های مختلف دستگاه

برنامه‌های Android باید با شرایط متغیر زیادی سازگار شوند: اندازه‌های پنجره، زبان‌های محلی، اندازه‌های قلم، زمینه‌های تیره و روشن، و غیره. بیشتر این شرایط از مقادیر سطح دستگاه مشتق می‌شوند که توسط کاربر کنترل می‌شوند و با نمونه Configuration فعلی نمایش داده می‌شوند. آزمایش پیکربندی‌های مختلف مستقیماً در آزمایش دشوار است زیرا آزمایش باید ویژگی‌های سطح دستگاه را پیکربندی کند.

DeviceConfigurationOverride یک میانای برنامه‌سازی کاربردی فقط آزمایشی است که به شما امکان می‌دهد پیکربندی‌های مختلف دستگاه را به‌صورت بومی‌سازی‌شده برای محتوای @Composable تحت آزمایش شبیه‌سازی کنید.

شیء همراه DeviceConfigurationOverride دارای توابع افزونه زیر است که ویژگی‌های پیکربندی سطح دستگاه را لغو می‌کند:

برای اعمال یک لغو خاص، محتوای تحت آزمایش را در یک فراخوانی به تابع سطح بالا DeviceConfigurationOverride() قرار دهید و لغو را به‌عنوان پارامتر ارسال کنید.

برای مثال، کد زیر لغو DeviceConfigurationOverride.ForcedSize() را برای تغییر تراکم به‌صورت محلی اعمال می‌کند و MyScreen قابل‌ترکیب را مجبور می‌کند در پنجره افقی بزرگ ارائه شود، حتی اگر دستگاهی که آزمایش روی آن اجرا می‌شود مستقیماً از آن اندازه پنجره پشتیبانی نکند:

composeTestRule.setContent {
    DeviceConfigurationOverride(
        DeviceConfigurationOverride.ForcedSize(DpSize(1280.dp, 800.dp))
    ) {
        MyScreen() // Will be rendered in the space for 1280dp by 800dp without clipping.
    }
}

برای اعمال چند لغو باهم، از DeviceConfigurationOverride.then() استفاده کنید:

composeTestRule.setContent {
    DeviceConfigurationOverride(
        DeviceConfigurationOverride.FontScale(1.5f) then
            DeviceConfigurationOverride.FontWeightAdjustment(200)
    ) {
        Text(text = "text with increased scale and weight")
    }
}

مدیریت سفارشی خطا در آزمایش‌ها

اشکال‌زدایی آزمایش‌های میانای کاربر اغلب مستلزم بازرسی وضعیت صفحه‌نمایش و سلسله‌مراتب ترکیب‌بندی درصورت ناموفق بودن ادعا است.

Compose یک خط لوله مدیریت خرابی بومی برای ساده‌سازی تشخیص ارائه می‌دهد. می‌توانید درصورت بروز خطا، به‌طور خودکار نماگرفت و سلسله‌مراتب واسط کاربر را ضبط کنید، یا گرداننده‌های سفارشی را برای ارسال دورسنجی خرابی به ابزارهای خارجی ثبت کنید.

پیکربندی رسیدگی به خطا

برای پیکربندی مدیریت خطا، شیء TestFailurePolicy را به ComposeUiTestConfig ارسال کنید.

ضبط آرتیفکت‌های خرابی داخلی

برای ضبط نماگرفت‌ها و سلسله‌مراتب میانای کاربری درصورت ناموفق بودن آزمایش، ویژگی‌های screenshotCaptureMode و uiHierarchyCaptureMode را در TestFailurePolicy تنظیم کنید.

class MyComposeTest {
    private val customConfig = ComposeUiTestConfig(
        failurePolicy = TestFailurePolicy(
            screenshotCaptureMode = TestFailurePolicy.CaptureMode.Enabled,
            uiHierarchyCaptureMode = TestFailurePolicy.CaptureMode.Enabled
        )
    )

    @Test
    fun myFirstTest() = runComposeUiTest(config = customConfig) {
        // ...
    }
}

استفاده از گرداننده خرابی سفارشی

برای تعریف رفتار سفارشی برای آزمایش‌های ناموفق، TestFailureHandler را به فهرست failureHandlers اضافه کنید. هر گرداننده یک شیء FailureContext دریافت می‌کند که حاوی خطای اصلی و فهرستی از مصنوعات تولیدشده توسط گرداننده‌های خط لوله قبلی است.

class MyComposeTestWithHandler {
    private val customConfig = ComposeUiTestConfig(
        failurePolicy = TestFailurePolicy(
            screenshotCaptureMode = TestFailurePolicy.CaptureMode.Enabled,
            failureHandlers = listOf(
                TestFailureHandler { context ->
                    val screenshot = context.artifacts.firstOrNull {
                        it.type == FailureArtifact.Type.Screenshot
                    }
                    // ...
                }
            )
        )
    )

    @get:Rule
    val rule = createComposeRule(config = customConfig)

    // ...
}

پیکربندی ضبط برای کل مجموعه آزمون

می‌توانید با ارسال آرگومان‌های اجراکننده ابزار دقیق در فایل build.gradle واحدتان، ضبط مصنوعات خرابی را برای کل مجموعه آزمون فعال کنید. این کار نیاز به به‌روزرسانی فایل‌های آزمایشی جداگانه را ازبین می‌برد.

// build.gradle.kts
android {
    defaultConfig {
        // ...
        testInstrumentationRunnerArguments["androidx.compose.ui.test.failure.isUiHierarchyCaptureEnabled"] = "true"
        testInstrumentationRunnerArguments["androidx.compose.ui.test.failure.isScreenshotCaptureEnabled"] = "true"
    }
}

اولویت پیکربندی

چارچوب هم TestFailurePolicy محلی و هم آرگومان‌های اجراکننده سطح مجموعه را ارزیابی می‌کند:

  • اگر صریحاً حالتی را روی CaptureMode.Enabled/Disabled در failurePolicy آزمایشی خود تنظیم کنید، این تنظیم بر آرگومان اجراکننده اولویت دارد.
  • اگر حالتی را روی CaptureMode.Unspecified تنظیم کنید (یا failurePolicy را به‌صورت null رها کنید)، چارچوب به شناسه اجراکننده برمی‌گردد.

منابع تکمیلی

  • آزمایش کردن برنامه‌ها در Android: صفحه مقصد اصلی آزمایش Android نمای گسترده‌تری از اصول و تکنیک‌های آزمایش ارائه می‌دهد.
  • مبانی آزمایش: درباره مفاهیم اصلی آزمایش کردن برنامه Android بیشتر بدانید.
  • آزمایش‌های محلی: می‌توانید برخی‌از آزمایش‌ها را به‌صورت محلی در ایستگاه کاری خودتان اجرا کنید.
  • آزمایش‌های ابزاردار: بهتر است آزمایش‌های ابزاردار را نیز اجرا کنید. یعنی آزمایش‌هایی که مستقیماً در دستگاه اجرا می‌شوند.
  • ادغام مداوم: ادغام مداوم به شما امکان می‌دهد آزمایش‌هایتان را در خط لوله استقرار خود ادغام کنید.
  • آزمایش اندازه‌های مختلف صفحه‌نمایش: با توجه به اینکه دستگاه‌های زیادی دردسترس کاربران است، باید اندازه‌های مختلف صفحه‌نمایش را آزمایش کنید.
  • Espresso: اگرچه Espresso برای واسط‌های کاربر مبتنی بر View طراحی شده است، اما دانش Espresso همچنان می‌تواند برای برخی جنبه‌های آزمایش Compose مفید باشد.