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 composable, mevcut Oluşturma'da birden fazla ekran ve pencere boyutunu test etmek için yapılandırma özelliklerini düzenler. 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. 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*).

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

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 veya emülatör gerekmez. Robolectric'i, diğer yararlı ö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 bilgiyi Robolectric Cihaz Yapılandırması dokümanlarında bulabilirsiniz.

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. Şu özelliklere sahip cihazlar için spesifikasyonları oluşturun: test stratejisi uygulamak için farklı ekran boyutlarına çalıştırılabilir. GMD'yi Sürekli Entegrasyon ile kullanarak (CI) olarak, gerektiğinde uygun testlerin yapıldığından emin olabilirsiniz, emülatörlerin sağlanması, başlatılması ve CI kurulumunuzun basitleştirilmesi.

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

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, ücretli bir ücretsiz katman kapsamındaki hizmet. 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 için Testlerinizi ölçeklendirmek için Gradle tarafından yönetilen cihazlar.

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. Genelde kullanıcı arayüzünüze test etmek için bunların tümünü veya çoğunu bir telefon form faktöründe, farklı ekran boyutlarına sahip cihazlar.

Belirli testlere yalnızca belirli cihazlarda çalıştırılacak ve daha sonra belirli testler Şu komutu çalıştıran komutu kullanarak AndroidJUnitRunner için bir bağımsız değişken testler.

Ö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, android.testInstrumentationRunnerArguments.annotation özelliğini kullanın. Örneğin projenin zamanlamasıyla ilgili (Gradle tarafından yönetilen cihazları kullanarak):

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

GMD 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ğunu kontrol edip ardından birine giderek aşağıdaki adımları izleyin:

$ ./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ı

Herhangi bir Espresso, Compose veya UI Automator testleri de dahil olmak üzere araçlı testlerin türü. 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 edip modudur. Espresso Cihazı ayrıca JUnit kurallarını ve ek açıklamaları kullanarak belirli özellikleri gerektirir:

@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ğıdakilere sahiptir: koşullar:

  • 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 Device, notlar kullanarak testleri filtrelemenize olanak tanımak için bağlı cihazların özelliklerini okuyabilir. Ek açıklamalı şartlar karşılanmazsa bu tür 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()))
    }
}

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

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ı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 yoğunluğu etkilenmezsiniz Bu nedenle, boyut hedef cihaza sığmıyorsa test bir UnsupportedDeviceOperationException ile başarısız olur. Test sırasında Bu örnekte, bu etiketleri filtrelemek için RequiresDisplay ek açıklamasını kullanın:

@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

Eyalet geri yüklemeyi test etmek için StateRestorationTester sınıfı kullanılır. derlenebilir bileşenlerle ilişkilendirmesine yardımcı olur. Bu, testleri daha hızlı hale getirir ve daha güvenlidir. Çünkü aktivite rekreasyon, birden çok aktivite içeren karmaşık bir süreçtir. senkronizasyon mekanizmaları:

@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ığı, testlerin gerçekleştirilmesi için pencere yönetimiyle ilgili özellikleri (etkinlik gibi) etkinleştirin veya doğrulayın Yerleştirme veya katlanabilir cihaz özelliklerini kullanıyor. Yapı, Google'ın Maven deposundan edinilebilir.

Örneğin, FoldingFeature() işlevini kullanarak bir Oluştur önizlemelerinde kullanabileceğiniz özel FoldingFeature. 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 kullanın. 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()))
    }
}

WindowManager projesinde daha fazla örnek bulabilirsiniz.

Ek kaynaklar

Belgeler

Örnekler

Codelab'ler