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

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

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ılması, kullanılabilir alandaki her düzene uyar. Bu özelliği kullanarak Tüm ekran boyutlarında kullanıcı arayüzü testi. Örneğin, küçük bir telefon form faktörü kullanabilirsiniz. büyük telefonlar, katlanabilir cihazlar ve cihazlar için kullanıcı arayüzü testleri de tabletler.

   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, bu composable'ı kullanarak yazı tipi ölçeğini, temaları ve diğer farklı pencere boyutlarında test etmek isteyebilirsiniz.

Robolektrik

JVM'de Compose veya görünüm tabanlı kullanıcı arayüzü testleri çalıştırmak için Robolectric'i kullanın yerel olarak: Cihaz veya emülatör gerekmez. Şunu yapılandırabilirsiniz: Diğer faydalı özelliklerin yanı sıra belirli ekran boyutlarını kullanmak için robotik.

Aşağıdaki Now in Android örneğinde, Robolectric yapılandırılmıştır. 1000x1000 dp ekran boyutunu 480 dpi çözünürlükte emüle etmek için:

@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, niteleyicileri test gövdesinden bu snippet'te Now in Android örneği:

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

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

RuntimeEnvironment.setQualifiers() uygulamasının sistemi güncellediğini ve kullanan ancak herhangi bir işlemi tetiklemeyen uygulama kaynakları aktif aktiviteler ya da diğer bileşenlerde kullanılabilir.

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 emülatörlerin ve gerçek cihazların özelliklerini tanımlamanıza olanak sağlar. araçlı testlerinizin çalıştırılması. Ş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

Firebase Test Lab'i (FTL) veya benzer bir cihaz çiftlik hizmetini kullanarak erişemeyeceğiniz belirli gerçek cihazlardaki testler (örneğin, katlanabilir cihazlar veya farklı boyutlardaki tabletler. Firebase Test Lab, ücretli bir ücretsiz katman kapsamındaki hizmet. FTL, emülatörlerde test çalıştırmayı da destekler. Bu hizmetler, araçlarlı testlerin güvenilirliğini ve hızını artırır çünkü cihazların ve emülatörlerin temel hazırlığını önceden yapabilirler.

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ısıyla filtrelemeyi test edin

Optimum test stratejisi aynı şeyi iki kez doğrulamamalıdır. Bu nedenle, Kullanıcı arayüzü testlerinin 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) şunu kullanarak testleri filtreleyebileceğini unutmayın: cihaz özellikleri.

Espresso Cihazı

Herhangi bir Espresso, Compose veya UI Automator testleri de dahil olmak üzere araçlı testlerin türü. Bu işlemler arasında ekran boyutunu ayarlamak veya katlanabilir cihaz durumlarını değiştirmek yer alabilir farklı duruşlar olabilir. Ö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 Cihazı, bağlı cihazların özelliklerini okuyarak şunları yapmanızı sağlar: notlar kullanarak testleri filtreleyin. Ek açıklamalı şartlar karşılanmazsa bu tür testler atlanır.

DemandDeviceMode ek açıklaması

RequiresDeviceMode ek açıklaması, bir öğenin birden fazla yalnızca DeviceMode değerlerinin tümünün desteklenmesi durumunda çalışacak bir test cihaz üzerinde.

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ı, öğenin genişliğini ve yüksekliğini belirtmenize olanak tanır. Cihaz ekranını göstermek için, boyut gruplarını tanımlayan boyut sınıflarını kullanın resmi pencere boyutu sınıflarına uyun.

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

Ekranları yeniden boyutlandır

Ekranın boyutlarını yeniden boyutlandırmak için setDisplaySize() yöntemini kullanın çalışma zamanında. Yöntemi DisplaySizeRule ile birlikte kullanın testler sırasında yapılan değişikliklerin deneyin.

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

StateRestorationTest Kullanıcısı

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ıya, Google'ın Maven deposu.

Örneğin, FoldingFeature() işlevini kullanarak bir Oluştur önizlemelerinde kullanabileceğiniz özel FoldingFeature. 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 kullanın. Aşağıdaki örnekte, bir FoldingFeature işlevi için HALF_OPENED ekranın ortasındaki dikey menteşeyi şu düzende olması beklenendir:

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