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 sunar.

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

DeviceConfigurationOverride composable, oluşturma 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ılması, mevcut alandaki her düzene uyar. Böylece kullanıcı arayüzü testlerini 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 için 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. Bir tablet düzeninin daha küçük bir form faktörüne sahip cihaza sığması için DeviceConfigurationOverride'ı kullanmak (ör. \*Now'ın Android sürümünde*).

Buna ek olarak, bu composable'ı yazı tipi ölçeğini, temaları ve farklı pencere boyutlarında test etmek isteyebileceğiniz diğer özellikleri ayarlamak için kullanabilirsiniz.

Robolektrik

JVM'de yerel olarak Compose veya görünüme dayalı kullanıcı arayüzü testleri çalıştırmak için Robolectric'i kullanın. Cihaz ya da emülatör gerekmez. Robolectric'i, diğer faydalı ö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 { ... }

Niteleyicileri, Now in Android örneğindeki bu snippet'te olduğu gibi, test gövdesinden de ayarlayabilirsiniz:

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

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

RuntimeEnvironment.setQualifiers() işlevinin, sistemi ve uygulama kaynaklarını yeni yapılandırmayla güncellediğini ancak etkin etkinlikler veya diğer bileşenlerde herhangi bir işlemi 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 gerektiğinde uygun testlerin çalıştırılmasını sağlayabilir, emülatörleri hazırlayabilir, 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 birden fazla GMD örneği bulabilirsiniz.

Firebase Test Lab

Firebase Test Lab'i (FTL) veya benzer bir cihaz çiftlik hizmetini kullanarak testlerinizi katlanabilir cihazlar ya da farklı boyutlardaki tabletler gibi erişiminizin olmayabileceği belirli cihazlarda çalıştırabilirsiniz. Firebase Test Lab, ücretsiz katmana sahip ücretli bir hizmettir. FTL, emülatörlerde test çalıştırmayı da destekler. Bu hizmetler, cihazları ve emülatörleri önceden sağlama imkanı sunduğu için araçlı testlerin 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ısıyla filtrelemeyi test edin

Optimum 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. Genelde kullanıcı arayüzü testlerinizi, hepsini veya çoğunu bir telefon form faktöründe, yalnızca bir kısmını farklı ekran boyutlarına sahip cihazlarda çalıştırarak filtrelersiniz.

Belirli testlere yalnızca belirli cihazlarla çalışacak şekilde açıklama ekleyebilir ve daha sonra, testleri çalıştıran komutu kullanarak AndroidJUnitRunner'a bir bağımsız değişken aktarabilirsiniz.

Ö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() {
        ...
    }

}

Daha sonra, testleri çalıştırırken belirli testleri filtrelemek için android.testInstrumentationRunnerArguments.annotation özelliğini kullanabilirsiniz. Örneğin, Gradle tarafından yönetilen cihazlar kullanıyorsanız:

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

GMD'yi kullanmıyorsanız ve CI üzerinde emülatörleri yönetiyorsanız öncelikle doğru emülatörün veya cihazın hazır ve bağlı olduğundan emin olun, ardından enstrümanlı 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 de filtreleyebileceğini unutmayın.

Espresso Cihazı

Espresso, Compose veya UI Automator testleri de dahil olmak üzere herhangi bir araçlı testi kullanarak testlerde emülatörlerde işlem yapmak için Espresso Cihaz'ı kullanın. Bu işlemler arasında ekran boyutunu ayarlamak veya katlanabilir cihaz durumlarını ya da duruşları açıp kapatmak yer alabilir. Örneğin, katlanabilir bir emülatörü kontrol edip masa üstü moduna ayarlayabilirsiniz. Espresso Cihaz, belirli özellikleri gerektiren JUnit kurallarını 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ı hâlâ alfa aşamasındadır ve aşağıdaki koşullara sahiptir:

  • Android Gradle Plugin 8.3 veya sonraki sürümler
  • Android Emulator 33.1.10 veya sonraki sürümler
  • API düzeyi 24 veya sonraki 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.

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

Görüntülü reklam ek açıklaması gerektirir

RequiresDisplay ek açıklaması, boyut sınıflarını kullanarak cihaz ekranının genişliğini ve yüksekliğini belirtmenize olanak tanır. Bu sınıflar, resmi pencere boyutu sınıflarının uyarınca boyut paketleri tanımlar.

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

Ekranları yeniden boyutlandır

Ç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 bu 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.
    }
}

StateRestorationTest Kullanıcısı

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ığı, pencere yönetimiyle ilgili etkinlik yerleştirme veya katlanabilir özellikler gibi özellikleri kullanan ya da bu özellikleri doğrulayan testler yazmanıza yardımcı olacak yardımcı programlar içerir. Yapıya Google'ın Maven deposu üzerinden erişilebilir.

Örneğin, Oluştur önizlemelerinde kullanabileceğiniz özel bir FoldingFeature oluşturmak için FoldingFeature() işlevini kullanabilirsiniz. Java'da createFoldingFeature() işlevini kullanın.

Compose ö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 görüntüleme özelliklerini emüle edebilirsiniz. Aşağıdaki örnekte ekranın ortasında HALF_OPENED dikey menteşesi olan bir FoldingFeature simüle edilmiş ve ardından düzenin beklenen düzen olup olmadığı kontrol edilmiştir:

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

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 projesinde daha fazla örnek bulabilirsiniz.

Ek kaynaklar

Dokümanlar

Numuneler

Codelab'ler