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.

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ı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 ü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 faydalı özelliklerin yanı sıra belirli ekran boyutlarını kullanacak şekilde yapılandırabilirsiniz.

Artık Android'de başlıklı makaledeki aşağıdaki örnekte, Robolectric 480 dpi çözünürlüğe sahip 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 { ... }

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, enstrümante edilmiş 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 cihazlar için özellikler 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ırlayarak ve başlatarak 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

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

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 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 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 olanları 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 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 Plugin 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 filtreleme

Espresso Device, notlar kullanarak testleri filtrelemenize olanak tanımak için bağlı cihazların özelliklerini okuyabilir. Ek açıklamalı gereksinimler karşılanmazsa testler atlanır.

RequiresDeviceMode ek açıklaması

RequiresDeviceMode ek açıklama, yalnızca cihazda DeviceMode değerlerinin tümü destekleniyorsa çalışacak 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.
    }
}

setDisplaySize() ile bir ekranın boyutunu değiştirdiğinizde 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 birleştirilebilir bileşenler için durum geri yüklemeyi test etmek amacıyla kullanılır. Etkinlik yeniden oluşturma işlemi birden fazla senkronizasyon mekanizması içeren karmaşık bir süreç olduğundan bu, testleri daha hızlı ve daha 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ı