هم‌کنش‌پذیری

Compose با چارچوب‌های آزمایشی رایج ادغام می‌شود.

هم‌کنش‌پذیری با Espresso

در برنامه ترکیبی، می‌توانید مؤلفه‌های Compose را در سلسله‌مراتب‌های نما و نماها را در composable-های Compose (ازطریق composable AndroidView) پیدا کنید.

برای مطابقت دادن هرکدام از این انواع، به مراحل خاصی نیاز نیست. نماها را با onView Espresso و عناصر Compose را با ComposeTestRule مطابقت می‌دهید.

@Test
fun androidViewInteropTest() {
    // Check the initial state of a TextView that depends on a Compose state.
    Espresso.onView(withText("Hello Views")).check(matches(isDisplayed()))
    // Click on the Compose button that changes the state.
    composeTestRule.onNodeWithText("Click here").performClick()
    // Check the new value.
    Espresso.onView(withText("Hello Compose")).check(matches(isDisplayed()))
}

افزودن معناشناسی با دامنه View برای آزمایش تعامل‌پذیری Compose

محدود کردن جستجوهای Compose به «نماهای» خاص

هنگام انتقال واسط‌های کاربر پیچیده به Compose، ممکن است با عناصر Compose یکسانی مواجه شوید که در چندین «نمای Android» سنتی تودرتو شده‌اند—مثلاً در یک RecyclerView یا ViewPager. در این سناریوها، جستجوی Compose استاندارد مثل onNodeWithText("Save") ممکن است با خطای «چند گره پیدا شد» ناموفق باشد.

به‌جای اصلاح کد تولید برای تزریق برچسب‌های آزمایشی پویا برای تشخیص این عناصر، می‌توانید آزمایش Compose خود را مستقیماً به یک نمای Android خاص محدود کنید.

از onRootWithViewInteraction API در قانون آزمایشی‌تان استفاده کنید. این تابع Espresso ViewInteraction را می‌پذیرد و به شما امکان می‌دهد از Espresso برای جداسازی یک View محفظه خاص و انجام تعاملات Compose منحصراً در آن سلسله‌مراتب محدودشده استفاده کنید.

تعامل با مورد فهرست

اگر لازم است با عنصر Compose در ردیف RecyclerView خاصی تعامل داشته باشید، از Espresso برای پیدا کردن ردیف استفاده کنید، سپس تعامل Compose را به آن محدود کنید. این کار عناصر Compose یکسان را در همه ردیف‌های دیگر نادیده می‌گیرد.

@Test
fun testComposeButtonInsideRecyclerViewItem() = runComposeUiTest {
    // Scroll to the desired position using Espresso
    Espresso.onView(withId(recyclerViewId))
        .perform(RecyclerViewActions.scrollToPosition<MyViewHolder>(3))

    // Define an Espresso ViewInteraction that uniquely identifies the row
    val rowView = Espresso.onView(
        allOf(
            withId(rootViewId),
            hasDescendant(withText("Item #3"))
        )
    )

    // Scope the Compose search strictly to that specific row View
    onRootWithViewInteraction(rowView)
        .onNode(hasText("Like"))
        .performClick()
}

رفع ابهام در ViewPagerها

وقتی چند قطعه با چیدمان‌های Compose یکسان به‌طور هم‌زمان در حافظه وجود دارد، می‌توانید جستجو را به شناسه View ریشه قطعه خاص محدود کنید تا از ابهام در تطابق جلوگیری شود.

@Test
fun testComposeButtonInsideViewPagerItem() = runComposeUiTest {
    // Swipe to the desired page using Espresso
    Espresso.onView(withId(viewPagerViewId)).perform(swipeLeft())

    // Identify the specific container view using Espresso
    val fragmentB = Espresso.onView(withId(fragmentRootViewId))

    // The generic text "Save" is now unique within this view scope
    onRootWithViewInteraction(fragmentB)
        .onNode(hasText("Save"))
        .assertIsDisplayed()
}

هم‌کنش‌پذیری با UiAutomator

به‌طور پیش‌فرض، ترکیب‌شدنی‌ها فقط ازطریق توصیف‌کننده‌های مناسبشان (نوشتار نمایش‌داده‌شده، شرح محتوا، و غیره) از UiAutomator قابل‌دسترسی هستند. اگر می‌خواهید به هر ترکیب‌پذیری که از Modifier.testTag استفاده می‌کند دسترسی داشته باشید، باید ویژگی معنایی testTagsAsResourceId را برای زیردرخت ترکیب‌پذیر خاص فعال کنید. فعال کردن این رفتار برای ترکیب‌شدنی‌هایی که هیچ شناسه منحصربه‌فرد دیگری ندارند، مانند ترکیب‌شدنی‌های پیمایش‌پذیر (برای مثال، LazyColumn)، مفید است.

Enable the semantic property only once high in your composables hierarchy to ensure all nested composables with Modifier.testTag are accessible from UiAutomator.

Scaffold(
    // Enables for all composables in the hierarchy.
    modifier = Modifier.semantics {
        testTagsAsResourceId = true
    }
){
    // Modifier.testTag is accessible from UiAutomator for composables nested here.
    LazyColumn(
        modifier = Modifier.testTag("myLazyColumn")
    ){
        // Content
    }
}

هر ترکیب‌پذیری با Modifier.testTag(tag) می‌تواند بااستفاده از By.res(resourceName) بااستفاده از همان tag به‌عنوان resourceName قابل‌دسترسی باشد.

val device = UiDevice.getInstance(getInstrumentation())

val lazyColumn: UiObject2 = device.findObject(By.res("myLazyColumn"))
// Some interaction with the lazyColumn.

منابع تکمیلی

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