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.

Cihaz Yapılandırmasını Geçersiz Kıl

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ılma özelliği, mevcut alandaki her düzene uyum sağlar. Böylece her ekran boyutunda kullanıcı arayüzü testi yapabilirsiniz. Ö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 yapmak 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üzenini \*Now in Android* gibi daha küçük bir form faktörüne sahip cihaza sığdırmak için DeviceConfigurationOverride'ı kullanma.

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.

Robolectric

JVM'de yerel olarak Oluşturma veya görüntülemeye dayalı kullanıcı arayüzü testleri çalıştırmak için Robofactric'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'da Android başlıklı 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 { ... }

Niteleyicileri, Now in Android örneğindeki şu snippet'te yapıldığı gibi de ayarlayabilirsiniz:

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

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

RuntimeEnvironment.setQualifiers() politikasının, sistemi ve uygulama kaynaklarını yeni yapılandırmayla güncellediğini ancak etkin etkinliklerde veya diğer bileşenlerde herhangi bir işlem tetiklemediğini unutmayın.

Robolectric Cihaz Yapılandırması dokümanlarından daha fazla bilgi edinebilirsiniz.

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 yürütülmesi gereken bir test stratejisi uygulamak için farklı ekran boyutlarına sahip cihazlara yönelik özellikler 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 birden fazla GMD örneği bulabilirsiniz.

Firebase Test Lab

Testlerinizi, erişiminiz olmayan belirli gerçek cihazlarda (ör. çeşitli boyutlardaki katlanabilir cihazlar veya tabletler) çalıştırmak için Firebase Test Lab'i (FTL) veya benzeri bir cihaz çiftliği 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 sağlayabildiği için araçlı testlerin 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 sayfasına bakın.

Test çalıştırıcıyla filtrelemeyi test etme

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. 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 ek açıklamalar 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 de kullanabilirsiniz:

class MyTestClass {

    @Test
    @TestExpandedWidth
    fun myExample_worksOnTablet() {
        ...
    }

    @Test
    @TestCompactWidth
    fun myExample_worksOnPortraitPhone() {
        ...
    }

}

Daha sonra, belirli testleri filtrelemek için testleri çalıştırırken 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ıyor ve CI üzerinde emülatör yönetiyorsanız öncelikle doğru emülatörün veya cihazın hazır ve bağlı olduğundan emin olun. Ardından parametreli testleri 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 gibi herhangi bir araçlı test türünü kullanarak yapılan testlerde emülatörler üzerinde işlem gerçekleştirmek için Espresso Cihazı kullanın. Bu işlemler arasında ekran boyutunu ayarlama veya katlanabilir cihaz durumunu ya da pozisyonunu açma/kapatma yer alabilir. Örneğin, katlanabilir bir emülatörü kontrol edebilir ve masa üstü moduna ayarlayabilirsiniz. Espresso Cihazı, belirli özellikleri zorunlu kılan 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 gereksinimlere sahip olduğunu unutmayın:

  • Android Gradle Plugin 8.3 veya üstü
  • Android Emulator 33.1.10 veya sonraki sürümler
  • API düzeyi 24 veya üstünü çalıştıran Android sanal cihazı

Testleri filtreleyin

Espresso Cihazı, ek açıklamalar kullanarak testleri filtrelemenizi sağlamak için bağlı cihazların özelliklerini okuyabilir. Ek açıklamalı gereksinimler karşılanmazsa testler atlanır.

DeviceMode ek açıklaması gerektirir

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

Display ek açıklaması gerektirir

RequiresDisplay ek açıklaması, resmi pencere boyutu sınıflarına uygun boyut paketlerini 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.
    }
}

Bir ekranı setDisplaySize() ile yeniden boyutlandırdığınızda cihazın yoğunluğunu etkilemezsiniz. Bu nedenle, bir boyut hedef cihaza sığmazsa UnsupportedDeviceOperationException ile test başarısız olur. Bu durumda testlerin çalıştırılmasını önlemek için RequiresDisplay ek açıklamasını kullanarak filtreleri 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.
    }
}

StateRestoration Test 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. Aktivite yeniden oluşturma birden fazla senkronizasyon mekanizmasına sahip karmaşık bir süreç olduğundan, bu da 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 özelliklere dayanan veya bu özellikleri doğrulayan testler yazmanıza yardımcı olacak yardımcı programlar içerir. Yapı, Google'ın Maven Repository deposu üzerinden kullanılabilir.

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

Oluşturma ö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ülü reklam özellikleri emülasyonu da yapabilirsiniz. Aşağıdaki örnekte, ekranın ortasında HALF_OPENED dikey menteşesi olan bir FoldingFeature simüle edilmiştir. Daha sonra, düzenin beklenen şekilde 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

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 uygulamaları