अलग-अलग स्क्रीन साइज़ की जांच करने के लिए लाइब्रेरी और टूल

Android, कई तरह के टूल और एपीआई उपलब्ध कराता है. इनकी मदद से, अलग-अलग स्क्रीन और विंडो साइज़ के लिए टेस्ट बनाए जा सकते हैं.

DeviceConfigurationOverride

DeviceConfigurationOverride कंपोज़ेबल की मदद से, कॉन्फ़िगरेशन एट्रिब्यूट को बदला जा सकता है. इससे Compose लेआउट में, स्क्रीन और विंडो के अलग-अलग साइज़ को टेस्ट किया जा सकता है. ForcedSize ओवरराइड, उपलब्ध जगह में किसी भी लेआउट के हिसाब से काम करता है. इससे आपको किसी भी स्क्रीन साइज़ पर कोई भी यूज़र इंटरफ़ेस (यूआई) टेस्ट चलाने की सुविधा मिलती है. उदाहरण के लिए, यूज़र इंटरफ़ेस (यूआई) से जुड़े सभी टेस्ट चलाने के लिए, छोटे फ़ोन का इस्तेमाल किया जा सकता है. इनमें बड़े फ़ोन, फ़ोल्ड किए जा सकने वाले फ़ोन, और टैबलेट के लिए यूज़र इंटरफ़ेस (यूआई) टेस्ट शामिल हैं.

   DeviceConfigurationOverride(
        DeviceConfigurationOverride.ForcedSize(DpSize(1280.dp, 800.dp))
    ) {
        MyScreen() // Will be rendered in the space for 1280dp by 800dp without clipping.
    }
पहली इमेज. \*Now in Android* में, छोटे डिवाइस पर टैबलेट लेआउट दिखाने के लिए DeviceConfigurationOverride का इस्तेमाल किया गया है.

इसके अलावा, इस कंपोज़ेबल का इस्तेमाल करके फ़ॉन्ट स्केल, थीम, और अन्य प्रॉपर्टी सेट की जा सकती हैं. इन प्रॉपर्टी को अलग-अलग विंडो साइज़ पर टेस्ट किया जा सकता है.

Robolectric

Robolectric का इस्तेमाल करके, JVM पर Compose या व्यू-आधारित यूज़र इंटरफ़ेस (यूआई) टेस्ट स्थानीय तौर पर चलाएं. इसके लिए, किसी डिवाइस या एम्युलेटर की ज़रूरत नहीं होती. Robolectric को, अन्य काम की प्रॉपर्टी के साथ-साथ स्क्रीन के खास साइज़ का इस्तेमाल करने के लिए कॉन्फ़िगर किया जा सकता है.

Now in Android के इस उदाहरण में, Robolectric को 480 डीपीआई के रिज़ॉल्यूशन के साथ 1000x1000 डीपी के स्क्रीन साइज़ का इस्तेमाल करने के लिए कॉन्फ़िगर किया गया है:

@RunWith(RobolectricTestRunner::class)
// Configure Robolectric to use a very large screen size that can fit all of the test sizes.
// This allows enough room to render the content under test without clipping or scaling.
@Config(qualifiers = "w1000dp-h1000dp-480dpi")
class NiaAppScreenSizesScreenshotTests { ... }

टेस्ट के मुख्य हिस्से से भी क्वालिफ़ायर सेट किए जा सकते हैं. जैसा कि Now in Android के इस उदाहरण में दिखाया गया है:

val (width, height, dpi) = ...

// Set qualifiers from specs.
RuntimeEnvironment.setQualifiers("w${width}dp-h${height}dp-${dpi}dpi")

ध्यान दें कि RuntimeEnvironment.setQualifiers(), सिस्टम और ऐप्लिकेशन के संसाधनों को नए कॉन्फ़िगरेशन के साथ अपडेट करता है. हालांकि, यह चालू गतिविधियों या अन्य कॉम्पोनेंट पर कोई कार्रवाई नहीं करता.

Robolectric के डिवाइस कॉन्फ़िगरेशन दस्तावेज़ में जाकर, इस बारे में ज़्यादा जानें.

Gradle मैनेज किए गए डिवाइस

Android Gradle प्लगिन में मौजूद Gradle-managed devices (GMD) की मदद से, उन एम्युलेटर और असली डिवाइसों के स्पेसिफ़िकेशन तय किए जा सकते हैं जिन पर आपकी इंस्ट्रुमेंटेड जांचें चलती हैं. अलग-अलग साइज़ की स्क्रीन वाले डिवाइसों के लिए स्पेसिफ़िकेशन बनाएं, ताकि टेस्टिंग की ऐसी रणनीति लागू की जा सके जिसमें कुछ टेस्ट, कुछ साइज़ की स्क्रीन पर ही किए जाने चाहिए. GMD को लगातार इंटिग्रेशन (सीआई) के साथ इस्तेमाल करके, यह पक्का किया जा सकता है कि ज़रूरत पड़ने पर सही टेस्ट किए जाएं. साथ ही, इससे इम्यूलेटर को चालू और लॉन्च किया जा सकता है. इसके अलावा, सीआई सेटअप को आसान बनाया जा सकता है.

android {
    testOptions {
        managedDevices {
            devices {
                // Run with ./gradlew nexusOneApi30DebugAndroidTest.
                nexusOneApi30(com.android.build.api.dsl.ManagedVirtualDevice) {
                    device = "Nexus One"
                    apiLevel = 30
                    // Use the AOSP ATD image for better emulator performance
                    systemImageSource = "aosp-atd"
                }
                // Run with ./gradlew  foldApi34DebugAndroidTest.
                foldApi34(com.android.build.api.dsl.ManagedVirtualDevice) {
                    device = "Pixel Fold"
                    apiLevel = 34
                    systemImageSource = "aosp-atd"
                }
            }
        }
    }
}

आपको testing-samples प्रोजेक्ट में, GMD के कई उदाहरण मिल सकते हैं.

Firebase टेस्ट लैब

Firebase Test Lab (FTL) या डिवाइस फ़ार्म की इसी तरह की किसी सेवा का इस्तेमाल करके, उन चुनिंदा असली डिवाइसों पर टेस्ट चलाएं जिन्हें शायद ऐक्सेस करने की अनुमति आपके पास न हो. जैसे, अलग-अलग साइज़ वाले फ़ोल्ड किए जा सकने वाले डिवाइस या टैबलेट. Firebase टेस्ट लैब, पैसे चुकाकर इस्तेमाल की जाने वाली सेवा है. हालांकि, इसे बिना किसी शुल्क के भी इस्तेमाल किया जा सकता है. FTL, एम्युलेटर पर भी टेस्ट चलाने की सुविधा देता है. ये सेवाएं, इंस्ट्रुमेंटेड टेस्टिंग की विश्वसनीयता और स्पीड को बेहतर बनाती हैं. ऐसा इसलिए, क्योंकि ये डिवाइसों और एम्युलेटर को पहले से ही उपलब्ध करा सकती हैं.

GMD के साथ FTL का इस्तेमाल करने के बारे में जानकारी के लिए, Gradle-managed devices की मदद से अपने टेस्ट को स्केल करना लेख पढ़ें.

टेस्ट रनर की मदद से फ़िल्टर करने की सुविधा की जांच करना

टेस्ट की सबसे सही रणनीति में, एक ही चीज़ की दो बार पुष्टि नहीं की जानी चाहिए. इसलिए, आपके ज़्यादातर यूज़र इंटरफ़ेस (यूआई) टेस्ट को कई डिवाइसों पर चलाने की ज़रूरत नहीं होती. आम तौर पर, यूज़र इंटरफ़ेस (यूआई) टेस्ट को फ़िल्टर करने के लिए, फ़ोन के फ़ॉर्म फ़ैक्टर पर सभी या ज़्यादातर टेस्ट चलाए जाते हैं. साथ ही, अलग-अलग स्क्रीन साइज़ वाले डिवाइसों पर सिर्फ़ कुछ टेस्ट चलाए जाते हैं.

कुछ टेस्ट को सिर्फ़ कुछ डिवाइसों पर चलाने के लिए एनोटेट किया जा सकता है. इसके बाद, टेस्ट चलाने वाले कमांड का इस्तेमाल करके, AndroidJUnitRunner को कोई तर्क दिया जा सकता है.

उदाहरण के लिए, अलग-अलग एनोटेशन बनाए जा सकते हैं:

annotation class TestExpandedWidth
annotation class TestCompactWidth

साथ ही, उन्हें अलग-अलग टेस्ट में इस्तेमाल करें:

class MyTestClass {

    @Test
    @TestExpandedWidth
    fun myExample_worksOnTablet() {
        ...
    }

    @Test
    @TestCompactWidth
    fun myExample_worksOnPortraitPhone() {
        ...
    }

}

इसके बाद, टेस्ट चलाते समय android.testInstrumentationRunnerArguments.annotation प्रॉपर्टी का इस्तेमाल करके, खास टेस्ट को फ़िल्टर किया जा सकता है. उदाहरण के लिए, अगर Gradle मैनेज किए जा रहे डिवाइसों का इस्तेमाल किया जा रहा है, तो:

$ ./gradlew pixelTabletApi30DebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.annotation='com.sample.TestExpandedWidth'

अगर GMD का इस्तेमाल नहीं किया जाता है और CI पर इम्यूलेटर मैनेज किए जाते हैं, तो सबसे पहले पक्का करें कि सही इम्यूलेटर या डिवाइस तैयार हो और कनेक्ट हो. इसके बाद, इंस्ट्रुमेंट की गई जांचों को चलाने के लिए, पैरामीटर को Gradle कमांड में से किसी एक पर पास करें:

$ ./gradlew connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.annotation='com.sample.TestExpandedWidth'

ध्यान दें कि Espresso Device (अगला सेक्शन देखें) भी डिवाइस की प्रॉपर्टी का इस्तेमाल करके, टेस्ट को फ़िल्टर कर सकता है.

एस्प्रेसो डिवाइस

Espresso Device का इस्तेमाल करके, किसी भी तरह के इंस्ट्रुमेंटेड टेस्ट में एम्युलेटर पर कार्रवाइयां करें. इनमें Espresso, Compose या UI Automator टेस्ट शामिल हैं. इन कार्रवाइयों में, स्क्रीन का साइज़ सेट करना या फ़ोल्ड किए जा सकने वाले डिवाइस की स्थितियों या पोस्चर को टॉगल करना शामिल हो सकता है. उदाहरण के लिए, फ़ोल्ड किए जा सकने वाले एम्युलेटर को कंट्रोल किया जा सकता है और उसे टेबलटॉप मोड पर सेट किया जा सकता है. Espresso Device में, JUnit के नियम और एनोटेशन भी शामिल होते हैं. इनकी मदद से, कुछ सुविधाओं को चालू किया जा सकता है:

@RunWith(AndroidJUnit4::class)
class OnDeviceTest {

    @get:Rule(order=1) val activityScenarioRule = activityScenarioRule<MainActivity>()

    @get:Rule(order=2) val screenOrientationRule: ScreenOrientationRule =
        ScreenOrientationRule(ScreenOrientation.PORTRAIT)

    @Test
    fun tabletopMode_playerIsDisplayed() {
        // Set the device to tabletop mode.
        onDevice().setTabletopMode()
        onView(withId(R.id.player)).check(matches(isDisplayed()))
    }
}

ध्यान दें कि Espresso Device अब भी ऐल्फ़ा स्टेज में है और इसके लिए ये ज़रूरी शर्तें हैं:

  • Android Gradle प्लगिन 8.3 या इसके बाद का वर्शन
  • Android Emulator 33.1.10 या इसके बाद का वर्शन
  • Android का वर्चुअल डिवाइस, जो एपीआई लेवल 24 या इसके बाद के वर्शन पर काम करता हो

फ़िल्टर टेस्ट

Espresso Device, कनेक्ट किए गए डिवाइसों की प्रॉपर्टी पढ़ सकता है. इससे आपको एनोटेशन का इस्तेमाल करके, टेस्ट फ़िल्टर करने में मदद मिलती है. अगर एनोटेट की गई ज़रूरी शर्तें पूरी नहीं होती हैं, तो टेस्ट छोड़ दिए जाते हैं.

RequiresDeviceMode एनोटेशन

RequiresDeviceMode एनोटेशन का इस्तेमाल कई बार किया जा सकता है. इससे यह पता चलता है कि कोई टेस्ट सिर्फ़ तब चलेगा, जब डिवाइस पर DeviceMode की सभी वैल्यू काम करती हों.

class OnDeviceTest {
    ...
    @Test
    @RequiresDeviceMode(TABLETOP)
    @RequiresDeviceMode(BOOK)
    fun tabletopMode_playerIdDisplayed() {
        // Set the device to tabletop mode.
        onDevice().setTabletopMode()
        onView(withId(R.id.player)).check(matches(isDisplayed()))
    }
}

RequiresDisplay एनोटेशन ज़रूरी है

RequiresDisplay एनोटेशन की मदद से, डिवाइस की स्क्रीन की चौड़ाई और लंबाई तय की जा सकती है. इसके लिए, साइज़ क्लास का इस्तेमाल किया जाता है. ये क्लास, डाइमेंशन बकेट तय करती हैं. ये बकेट, विंडो के साइज़ की आधिकारिक क्लास के मुताबिक होती हैं.

class OnDeviceTest {
    ...
    @Test
    @RequiresDisplay(EXPANDED, COMPACT)
    fun myScreen_expandedWidthCompactHeight() {
        ...
    }
}

डिसप्ले का साइज़ बदलना

स्क्रीन के डाइमेंशन का साइज़ रनटाइम में बदलने के लिए, setDisplaySize() तरीके का इस्तेमाल करें. इस तरीके का इस्तेमाल DisplaySizeRule क्लास के साथ करें. इससे यह पक्का किया जा सकेगा कि टेस्ट के दौरान किए गए सभी बदलाव, अगले टेस्ट से पहले पहले जैसे हो जाएं.

@RunWith(AndroidJUnit4::class)
class ResizeDisplayTest {

    @get:Rule(order = 1) val activityScenarioRule = activityScenarioRule<MainActivity>()

    // Test rule for restoring device to its starting display size when a test case finishes.
    @get:Rule(order = 2) val displaySizeRule: DisplaySizeRule = DisplaySizeRule()

    @Test
    fun resizeWindow_compact() {
        onDevice().setDisplaySize(
            widthSizeClass = WidthSizeClass.COMPACT,
            heightSizeClass = HeightSizeClass.COMPACT
        )
        // Verify visual attributes or state restoration.
    }
}

setDisplaySize() की मदद से डिसप्ले का साइज़ बदलने पर, डिवाइस की डेंसिटी पर कोई असर नहीं पड़ता. इसलिए, अगर कोई डाइमेंशन टारगेट डिवाइस में फ़िट नहीं होता है, तो टेस्ट में UnsupportedDeviceOperationException दिखता है. इस मामले में टेस्ट को चलने से रोकने के लिए, RequiresDisplay एनोटेशन का इस्तेमाल करके उन्हें फ़िल्टर करें:

@RunWith(AndroidJUnit4::class)
class ResizeDisplayTest {

    @get:Rule(order = 1) var activityScenarioRule = activityScenarioRule<MainActivity>()

    // Test rule for restoring device to its starting display size when a test case finishes.
    @get:Rule(order = 2) var displaySizeRule: DisplaySizeRule = DisplaySizeRule()

    /**
     * Setting the display size to EXPANDED would fail in small devices, so the [RequiresDisplay]
     * annotation prevents this test from being run on devices outside the EXPANDED buckets.
     */
    @RequiresDisplay(
        widthSizeClass = WidthSizeClassEnum.EXPANDED,
        heightSizeClass = HeightSizeClassEnum.EXPANDED
    )
    @Test
    fun resizeWindow_expanded() {
        onDevice().setDisplaySize(
            widthSizeClass = WidthSizeClass.EXPANDED,
            heightSizeClass = HeightSizeClass.EXPANDED
        )
        // Verify visual attributes or state restoration.
    }
}

StateRestorationTester

StateRestorationTester क्लास का इस्तेमाल, कंपोज़ेबल कॉम्पोनेंट के लिए स्टेट रीस्टोर करने की सुविधा को टेस्ट करने के लिए किया जाता है. इससे गतिविधियों को फिर से बनाने की ज़रूरत नहीं पड़ती. इससे टेस्ट ज़्यादा तेज़ी से और ज़्यादा भरोसेमंद तरीके से किए जा सकते हैं. ऐसा इसलिए, क्योंकि गतिविधि को फिर से बनाने की प्रोसेस काफ़ी मुश्किल होती है. इसमें कई सिंक्रनाइज़ेशन मैकेनिज़्म शामिल होते हैं:

@Test
fun compactDevice_selectedEmailEmailRetained_afterConfigChange() {
    val stateRestorationTester = StateRestorationTester(composeTestRule)

    // Set content through the StateRestorationTester object.
    stateRestorationTester.setContent {
        MyApp()
    }

    // Simulate a config change.
    stateRestorationTester.emulateSavedInstanceStateRestore()
}

Window Testing library

Window Testing लाइब्रेरी में ऐसी सुविधाएं होती हैं जिनकी मदद से, ऐसी जांचें लिखी जा सकती हैं जो विंडो मैनेजमेंट से जुड़ी सुविधाओं पर निर्भर करती हैं या उनकी पुष्टि करती हैं. जैसे, ऐक्टिविटी एम्बेड करना या फ़ोल्ड किए जा सकने वाले डिवाइसों से जुड़ी सुविधाएं. यह आर्टफ़ैक्ट, Google के Maven Repository के ज़रिए उपलब्ध है.

उदाहरण के लिए, FoldingFeature() फ़ंक्शन का इस्तेमाल करके, कस्टम FoldingFeature जनरेट किया जा सकता है. इसका इस्तेमाल, कंपोज़ की झलक में किया जा सकता है. Java में, createFoldingFeature() फ़ंक्शन का इस्तेमाल करें.

ईमेल लिखने की झलक में, FoldingFeature को इस तरह लागू किया जा सकता है:

@Preview(showBackground = true, widthDp = 480, heightDp = 480)
@Composable private fun FoldablePreview() =
    MyApplicationTheme {
        ExampleScreen(
            displayFeatures = listOf(FoldingFeature(Rect(0, 240, 480, 240)))
        )
 }

इसके अलावा, TestWindowLayoutInfo() फ़ंक्शन का इस्तेमाल करके, यूज़र इंटरफ़ेस (यूआई) टेस्ट में डिसप्ले सुविधाओं को एम्युलेट किया जा सकता है. नीचे दिए गए उदाहरण में, स्क्रीन के बीच में HALF_OPENED वर्टिकल हिंज के साथ FoldingFeature को सिम्युलेट किया गया है. इसके बाद, यह जांच की गई है कि लेआउट उम्मीद के मुताबिक है या नहीं:

Compose

import androidx.window.layout.FoldingFeature.Orientation.Companion.VERTICAL
import androidx.window.layout.FoldingFeature.State.Companion.HALF_OPENED
import androidx.window.testing.layout.FoldingFeature
import androidx.window.testing.layout.TestWindowLayoutInfo
import androidx.window.testing.layout.WindowLayoutInfoPublisherRule

@RunWith(AndroidJUnit4::class)
class MediaControlsFoldingFeatureTest {

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

    @get:Rule(order=2)
    val windowLayoutInfoPublisherRule = WindowLayoutInfoPublisherRule()

    @Test
    fun foldedWithHinge_foldableUiDisplayed() {
        composeTestRule.setContent {
            MediaPlayerScreen()
        }

        val hinge = FoldingFeature(
            activity = composeTestRule.activity,
            state = HALF_OPENED,
            orientation = VERTICAL,
            size = 2
        )

        val expected = TestWindowLayoutInfo(listOf(hinge))
        windowLayoutInfoPublisherRule.overrideWindowLayoutInfo(expected)

        composeTestRule.waitForIdle()

        // Verify that the folding feature is detected and media controls shown.
        composeTestRule.onNodeWithTag("MEDIA_CONTROLS").assertExists()
    }
}

व्यू

import androidx.window.layout.FoldingFeature.Orientation
import androidx.window.layout.FoldingFeature.State
import androidx.window.testing.layout.FoldingFeature
import androidx.window.testing.layout.TestWindowLayoutInfo
import androidx.window.testing.layout.WindowLayoutInfoPublisherRule

@RunWith(AndroidJUnit4::class)
class MediaControlsFoldingFeatureTest {

    @get:Rule(order=1)
    val activityRule = ActivityScenarioRule(MediaPlayerActivity::class.java)

    @get:Rule(order=2)
    val windowLayoutInfoPublisherRule = WindowLayoutInfoPublisherRule()

    @Test
    fun foldedWithHinge_foldableUiDisplayed() {
        activityRule.scenario.onActivity { activity ->
            val feature = FoldingFeature(
                activity = activity,
                state = State.HALF_OPENED,
                orientation = Orientation.VERTICAL)
            val expected = TestWindowLayoutInfo(listOf(feature))
            windowLayoutInfoPublisherRule.overrideWindowLayoutInfo(expected)
        }

        // Verify that the folding feature is detected and media controls shown.
        onView(withId(R.id.media_controls)).check(matches(isDisplayed()))
    }
}

आपको WindowManager प्रोजेक्ट में और भी सैंपल मिल सकते हैं.

अन्य संसाधन

दस्तावेज़

सैंपल

कोडलैब