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

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 को कॉन्फ़िगर किया जा सकता है, ताकि वह कुछ खास स्क्रीन साइज़ के साथ-साथ अन्य काम की प्रॉपर्टी का इस्तेमाल कर सके.

Android में अब उपलब्ध है से मिले इस उदाहरण में, Robolectric को 480 डीपीआई के रिज़ॉल्यूशन के साथ 1,000 x 1,000 डीपी के स्क्रीन साइज़ को एमुलेट करने के लिए कॉन्फ़िगर किया गया है:

@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 { ... }

अब Android पर उपलब्ध है उदाहरण के इस स्निपेट में दिखाए गए तरीके से, टेस्ट बॉडी से भी क्वालीफ़ायर सेट किए जा सकते हैं:

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

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

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

ज़्यादा जानकारी के लिए, Robolectric डिवाइस कॉन्फ़िगरेशन दस्तावेज़ पढ़ें.

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

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

Firebase टेस्ट लैब

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

GMD के साथ FTL का इस्तेमाल करने के बारे में जानने के लिए, Gradle से मैनेज किए जा रहे डिवाइसों की मदद से, अपने टेस्ट को बड़े पैमाने पर चलाना लेख पढ़ें.

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

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

कुछ टेस्ट को सिर्फ़ कुछ डिवाइसों पर चलाने के लिए एनोटेट किया जा सकता है. इसके बाद, टेस्ट चलाने वाले कमांड का इस्तेमाल करके, 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 का इस्तेमाल नहीं किया जा रहा है और सीआई पर एमुलेटर मैनेज किए जा रहे हैं, तो सबसे पहले पक्का करें कि सही एमुलेटर या डिवाइस तैयार और कनेक्ट हो. इसके बाद, इंस्ट्रूमेंट किए गए टेस्ट चलाने के लिए, पैरामीटर को Gradle के किसी एक निर्देश में पास करें:

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

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

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

Espresso डिवाइस का इस्तेमाल करके, टेस्ट में एमुलेटर पर कार्रवाइयां करें. इसके लिए, किसी भी तरह के इंस्ट्रुमेंट किए गए टेस्ट का इस्तेमाल करें. इनमें 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 डिवाइस अब भी अल्फा स्टेज में है. साथ ही, इसके लिए ये ज़रूरी शर्तें पूरी करनी होंगी:

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

टेस्ट फ़िल्टर करना

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

विंडो टेस्टिंग लाइब्रेरी

विंडो टेस्टिंग लाइब्रेरी में ऐसी सुविधाएं होती हैं जिनकी मदद से, विंडो मैनेजमेंट से जुड़ी सुविधाओं पर आधारित टेस्ट लिखे जा सकते हैं या उनकी पुष्टि की जा सकती है. जैसे, गतिविधि को एम्बेड करना या फ़ोल्ड करने की सुविधाएं. आर्टफ़ैक्ट, 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 प्रोजेक्ट में आपको और भी सैंपल मिल सकते हैं.

अन्य संसाधन

दस्तावेज़

सैंपल

कोडलैब