Farklı ekran boyutlarını test etmek için kitaplıklar ve araçlar

Android, farklı ekran ve pencere boyutları için testler oluşturmanıza yardımcı olabilecek çeşitli araçlar ve API'ler sağlar.

CihazYapılandırmasını Geçersiz Kılma

DeviceConfigurationOverride bileşeni, Compose düzenlerinde birden fazla ekran ve pencere boyutunu test etmek için yapılandırma özelliklerini geçersiz kılmanıza olanak tanır. ForcedSize geçersiz kılma, mevcut alandaki tüm düzenlere uyar. Böylece, herhangi bir kullanıcı arayüzü testini herhangi bir ekran boyutunda çalıştırabilirsiniz. Örneğin, büyük telefonlar, katlanabilir cihazlar ve tabletler için kullanıcı arayüzü testleri de dahil olmak üzere tüm kullanıcı arayüzü testlerinizi çalıştırmak üzere küçük bir telefon form faktörü kullanabilirsiniz.

   DeviceConfigurationOverride(
        DeviceConfigurationOverride.ForcedSize(DpSize(1280.dp, 800.dp))
    ) {
        MyScreen() // Will be rendered in the space for 1280dp by 800dp without clipping.
    }
Şekil 1. \*Android'de kullanıma sunuldu*
bölümünde olduğu gibi, tablet düzenini daha küçük form faktörlü bir cihaza sığdırmak için DeviceConfigurationOverride'ı kullanma

Ayrıca, yazı tipi ölçeğini, temaları ve farklı pencere boyutlarında test etmek isteyebileceğiniz diğer özellikleri ayarlamak için bu bileşiği kullanabilirsiniz.

Robolectric

Robolectric'i kullanarak Compose veya görünüme dayalı kullanıcı arayüzü testlerini JVM'de yerel olarak çalıştırın. Cihaz veya emülatör gerekmez. Robolectric'i, diğer yararlı özelliklerin yanı sıra belirli ekran boyutlarını kullanacak şekilde yapılandırabilirsiniz.

Now in Android programındaki aşağıdaki örnekte, Robolectric 1000x1000 dp ekran boyutunu 480 dpi çözünürlükte emüle edecek şekilde yapılandırılmıştır:

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

Ayrıca, Artık Android'de örneğindeki bu snippet'te yapıldığı gibi test gövdesinden de nitelikleri ayarlayabilirsiniz:

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

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

RuntimeEnvironment.setQualifiers()'ün sistemi ve uygulama kaynaklarını yeni yapılandırmaya güncellediğini ancak etkin etkinliklerde veya diğer bileşenlerde herhangi bir işlem tetiklemediğini unutmayın.

Daha fazla bilgi için Robolectric Cihaz Yapılandırması dokümanlarına bakın.

Gradle tarafından yönetilen cihazlar

Gradle tarafından yönetilen cihazlar (GMD) Android Gradle eklentisi, araçlı testlerinizin çalıştırıldığı emülatörlerin ve gerçek cihazların özelliklerini tanımlamanızı sağlar. Belirli testlerin belirli ekran boyutlarında çalıştırılmasını gerektiren bir test stratejisi uygulamak için farklı ekran boyutlarına sahip cihazlara yönelik spesifikasyonlar oluşturun. GMD'yi Sürekli Entegrasyon (CI) ile kullanarak gerekli olduğunda uygun testlerin yapılmasını sağlayabilir, emülatörleri hazırlayıp başlatabilir ve CI kurulumunuzu basitleştirebilirsiniz.

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 projesinde GMD'ye ait birden fazla örnek bulabilirsiniz.

Firebase Test Lab

Testlerinizi, erişiminiz olmayabilecek belirli gerçek cihazlarda (ör. katlanabilir cihazlar veya farklı boyutlarda tabletler) çalıştırmak için Firebase Test Lab'i (FTL) ya da benzer bir cihaz çiftliği hizmetini kullanın. Firebase Test Lab, ücretsiz katmanı olan ücretli bir hizmettir. FTL, testlerin emülatörlerde çalıştırılmasını da destekler. Bu hizmetler, cihazları ve emülatörleri önceden hazırlayarak araç destekli testin güvenilirliğini ve hızını artırır.

GMD ile FTL'yi kullanma hakkında bilgi edinmek için Gradle tarafından yönetilen cihazlarla testlerinizi ölçeklendirme başlıklı makaleyi inceleyin.

Test çalıştırıcı ile filtrelemeyi test etme

Optimal bir test stratejisi aynı şeyi iki kez doğrulamamalıdır. Bu nedenle, kullanıcı arayüzü testlerinizin çoğunun birden fazla cihazda çalıştırılması gerekmez. Genellikle kullanıcı arayüzü testlerinizin tümünü veya çoğunu bir telefon form faktöründe, yalnızca bir alt kümesini ise farklı ekran boyutlarına sahip cihazlarda çalıştırarak filtrelersiniz.

Belirli testleri yalnızca belirli cihazlarla çalıştırılacak şekilde ek açıklamayla işaretleyebilir ve ardından testleri çalıştıran komutu kullanarak AndroidJUnitRunner'a bir bağımsız değişken iletebilirsiniz.

Örneğin, farklı ek açıklamalar oluşturabilirsiniz:

annotation class TestExpandedWidth
annotation class TestCompactWidth

Bunları farklı testlerde kullanabilirsiniz:

class MyTestClass {

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

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

}

Ardından, testleri çalıştırırken belirli testleri filtrelemek için android.testInstrumentationRunnerArguments.annotation mülkünü kullanabilirsiniz. Örneğin, Gradle tarafından yönetilen cihazlar kullanıyorsanız:

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

GMD kullanmıyorsanız ve CI'de emülatörleri yönetiyorsanız önce doğru emülatör veya cihazın hazır ve bağlı olduğundan emin olun, ardından enstrümante edilmiş testleri çalıştırmak için parametreyi Gradle komutlarından birine iletin:

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

Espresso cihazının (sonraki bölüme bakın) cihaz özelliklerini kullanarak testleri filtreleyebileceğini unutmayın.

Espresso Cihazı

Espresso, Compose veya UI Automator testleri dahil olmak üzere her tür enstrümante edilmiş testleri kullanarak testlerde emülatörlerde işlem yapmak için Espresso Device'ı kullanın. Ekran boyutunu ayarlama veya katlanabilir durumları ya da duruşları değiştirme bu işlemler arasında yer alabilir. Örneğin, katlanabilir bir emülatör kontrol edebilir ve masaüstü moduna ayarlayabilirsiniz. Espresso Device, belirli özellikleri zorunlu kılmak için JUnit kuralları ve ek açıklamaları da içerir:

@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 cihazının hâlâ alfa aşamasında olduğunu ve aşağıdaki koşulları karşıladığını unutmayın:

  • Android Gradle eklentisi 8.3 veya sonraki sürümler
  • Android Emulator 33.1.10 veya sonraki sürümler
  • API seviyesi 24 veya daha yeni sürümleri çalıştıran Android sanal cihaz

Testleri filtrele

Espresso Cihazı, bağlı cihazların özelliklerini okuyabilir. Böylece, notlar kullanarak testleri filtreleyebilirsiniz. Ek açıklamalı gereksinimler karşılanmazsa testler atlanır.

RequiresDeviceMode ek açıklaması

RequiresDeviceMode ek açıklaması, yalnızca DeviceMode değerlerinin tümünün cihazda desteklenmesi durumunda çalıştırılacak bir testi belirtmek için birden çok kez kullanılabilir.

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 ek açıklaması

RequiresDisplay ek açıklaması, resmi pencere boyutu sınıflarına uygun olarak boyut gruplarını tanımlayan boyut sınıflarını kullanarak cihaz ekranının genişliğini ve yüksekliğini belirtmenize olanak tanır.

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

Ekranları yeniden boyutlandırma

Çalışma zamanında ekranın boyutlarını yeniden boyutlandırmak için setDisplaySize() yöntemini kullanın. Yöntemi DisplaySizeRule sınıfıyla birlikte kullanın. Bu sınıf, testler sırasında yapılan değişikliklerin bir sonraki testten önce geri alınmasını sağlar.

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

Bir ekranı setDisplaySize() ile yeniden boyutlandırdığınızda cihazın yoğunluğu etkilenmez. Bu nedenle, boyut hedef cihaza sığmıyorsa testte UnsupportedDeviceOperationException değeri bulunmaz. Bu durumda testlerin çalıştırılmasını önlemek için RequiresDisplay ek açıklamasını kullanarak testleri filtreleyin:

@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 sınıfı, etkinlikleri yeniden oluşturmadan composable bileşenler için durum geri yükleme işlemini test etmek amacıyla kullanılır. Aktiviteyi yeniden oluşturma, birden fazla senkronizasyon mekanizmasına sahip karmaşık bir işlem olduğundan testleri daha hızlı ve güvenilir hale getirir:

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

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

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

Pencere Testi kitaplığı

Pencere Testi kitaplığı, etkinlik yerleştirme veya katlanabilir özellikler gibi pencere yönetimiyle ilgili özellikleri kullanan ya da doğrulayan testler yazmanıza yardımcı olacak yardımcı programlar içerir. Öğe, Google'ın Maven deposundan edinilebilir.

Örneğin, FoldingFeature() işlevini kullanarak özel bir FoldingFeature oluşturabilir ve bu özel FoldingFeature'i Oluştur önizlemelerinde kullanabilirsiniz. Java'da createFoldingFeature() işlevini kullanın.

Oluştur önizlemesinde FoldingFeature öğesini aşağıdaki şekilde uygulayabilirsiniz:

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

Ayrıca, TestWindowLayoutInfo() işlevini kullanarak kullanıcı arayüzü testlerinde ekran özelliklerini taklit edebilirsiniz. Aşağıdaki örnekte, ekranın ortasında HALF_OPENED dikey menteşe bulunan bir FoldingFeature simüle edilerek düzenin beklenen düzen olup olmadığı kontrol edilir:

Oluştur

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

Görüntüleme sayısı

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

Daha fazla örnek için WindowManager projesine göz atın.

Ek kaynaklar

Belgeler

Örnekler

Codelab uygulamaları