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.

DeviceConfigurationOverride

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. Bu sayede, herhangi bir ekran boyutunda herhangi bir kullanıcı arayüzü testi ç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. \*Now in Android*'de olduğu gibi, tablet düzenini daha küçük form faktörlü bir cihaza sığdırmak için DeviceConfigurationOverride kullanma

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

Robolectric

JVM'de Compose veya görünüm tabanlı kullanıcı arayüzü testlerini yerel olarak çalıştırmak için Robolectric'i kullanın. Cihaz veya 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'deki aşağıdaki örnekte Robolectric, 480 dpi çözünürlükte 1000x1000 dp ekran boyutunu taklit 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 yapıldığı 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(), sistem ve uygulama kaynaklarını yeni yapılandırmayla günceller ancak etkin etkinliklerde veya diğer bileşenlerde herhangi bir işlemi tetiklemez.

Robolectric Cihaz Yapılandırması belgelerinden daha fazla bilgi edinebilirsiniz.

Gradle tarafından yönetilen cihazlar

Gradle tarafından yönetilen cihazlar (GMD) Android Gradle eklentisi, enstrümantasyon testlerinizin çalıştırıldığı emülatörlerin ve gerçek cihazların özelliklerini tanımlamanıza olanak tanır. Belirli testlerin belirli ekran boyutlarında çalıştırılması gereken 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 uygun testlerin gerektiğinde çalıştırı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 ile ilgili birden fazla örnek bulabilirsiniz.

Firebase Test Lab

Erişiminiz olmayan belirli gerçek cihazlarda (ör. farklı boyutlardaki katlanabilir cihazlar veya tabletler) testlerinizi çalıştırmak için Firebase Test Lab (FTL) veya benzer bir cihaz grubu hizmetini kullanın. Firebase Test Lab, ücretsiz katmanı olan ücretli bir hizmettir. FTL, emülatörlerde test çalıştırmayı da destekler. Bu hizmetler, cihazları ve emülatörleri önceden hazırlayabildiği için enstrümantasyon testinin güvenilirliğini ve hızını artırır.

FTL'yi GMD ile 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 test filtreleme

En uygun 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ü testlerinizi, hepsini veya çoğunu bir telefon form faktöründe ve yalnızca bir alt kümesini farklı ekran boyutlarına sahip cihazlarda çalıştırarak filtrelersiniz.

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

Örneğin, farklı notlar oluşturabilirsiniz:

annotation class TestExpandedWidth
annotation class TestCompactWidth

Bunları farklı testlerde kullanın:

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 özelliğini 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 emülatörleri CI'da yönetiyorsanız öncelikle doğru emülatörün veya cihazın hazır ve bağlı olduğundan emin olun, ardından parametreyi Gradle komutlarından birine ileterek enstrümantasyon testlerini çalıştırın:

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

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

Espresso Cihazı

Espresso, Compose veya UI Automator testleri de dahil olmak üzere her türlü enstrümantasyon testini kullanarak testlerde emülatörler üzerinde işlem yapmak için Espresso Device'ı kullanın. Bu işlemler arasında ekran boyutunu ayarlama veya katlanabilir durumlar ya da duruşlar arasında geçiş yapma yer alabilir. Örneğin, katlanabilir bir emülatörü kontrol edebilir ve masaüstü moduna ayarlayabilirsiniz. Espresso Device, belirli özellikleri gerektiren 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 Device'ın hâlâ alfa aşamasında olduğunu ve aşağıdaki şartlara tabi olduğunu unutmayın:

  • Android Gradle eklentisi 8.3 veya sonraki sürümler
  • Android Emulator 33.1.10 veya sonraki sürümler
  • API düzeyi 24 veya daha yüksek bir sürümü çalıştıran Android sanal cihazı

Testleri filtreleme

Espresso Device, bağlı cihazların özelliklerini okuyarak testleri notlar kullanarak filtrelemenize olanak tanır. Ek açıklamalı koşullar karşılanmazsa testler atlanır.

RequiresDeviceMode ek açıklaması

RequiresDeviceMode ek açıklaması, yalnızca cihazda DeviceMode değerlerinin tümü destekleniyorsa çalıştırılacak bir testi belirtmek için birden fazla 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ını izleyen 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. Bu yöntemi, testler sırasında yapılan değişikliklerin bir sonraki testten önce geri alınmasını sağlayan DisplaySizeRule sınıfıyla birlikte kullanın.

@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() ile bir ekranı yeniden boyutlandırdığınızda cihazın yoğunluğunu etkilemezsiniz. Bu nedenle, bir boyut hedef cihaza sığmazsa test UnsupportedDeviceOperationException ile başarısız olur. 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şenlerin durum geri yüklemesini test etmek için kullanılır. Bu sayede testler daha hızlı ve daha güvenilir hale gelir. Çünkü etkinliğin yeniden oluşturulması, birden fazla senkronizasyon mekanizması içeren karmaşık bir süreçtir:

@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 kitaplığı

Pencere Testi kitaplığı, etkinlik yerleştirme veya katlanabilir özellikler gibi pencere yönetimiyle ilgili özelliklere dayalı ya da bu özellikleri doğrulayan testler yazmanıza yardımcı olan yardımcı programlar içerir. Yapı, Google'ın Maven deposu üzerinden kullanılabilir.

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

Oluşturma önizlemesinde FoldingFeature öğesini şu ş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 dikey menteşesi olan bir FoldingFeature simüle edilmekte ve ardından düzenin beklenen düzen olup olmadığı kontrol edilmektedir: HALF_OPENED

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

WindowManager projesinde daha fazla örnek bulabilirsiniz.

Ek kaynaklar

Belgeler

Örnekler

Codelab uygulamaları