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 composable'ı, 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ü testini ç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.
    }
1. Şekil. \*Now in Android* uygulamasında olduğu gibi, bir tablet düzenini daha küçük bir form faktörlü cihaza sığdırmak için DeviceConfigurationOverride'ı kullanma.

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

Robolectric

Compose veya görünüm tabanlı kullanıcı arayüzü testlerini JVM'de Robolectric kullanarak 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.

Now in Android'deki aşağıdaki örnekte, Robolectric 480 dpi çözünürlükle 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, Android'de Yenilikler örneğindeki bu snippet'te gösterildiği gibi, test gövdesinden niteleyicileri 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.

Daha fazla bilgiyi Robolectric Cihaz Yapılandırması belgelerinde bulabilirsiniz.

Gradle tarafından yönetilen cihazlar

Gradle tarafından yönetilen cihazlar (GMD) Android Gradle eklentisi, enstrümanlı testlerinizin çalışacağı 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 özellikler oluşturun. GMD'yi Sürekli Entegrasyon (CI) ile kullanarak gerektiğinde uygun testlerin çalıştırılmasını, emülatörlerin sağlanmasını ve başlatılmasını, ayrıca CI kurulumunuzun basitleştirilmesini sağlayabilirsiniz.

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

Katlanabilir telefonlar veya farklı boyutlarda tabletler gibi erişiminizin olmadığı belirli gerçek cihazlarda testlerinizi çalıştırmak için Firebase Test Lab (FTL) veya benzer bir cihaz çiftliği hizmeti 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ğlayabildikleri için enstrümanlı 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 başlıklı makaleyi inceleyin.

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

En iyi test stratejisi, aynı şeyi iki kez doğrulamaz. Bu nedenle, kullanıcı arayüzü testlerinizin çoğu birden fazla cihazda çalıştırılmak zorunda değildir. Genellikle, kullanıcı arayüzü testlerinizi filtrelemek için tümünü veya çoğunu telefon form faktöründe, yalnızca bir alt kümesini ise farklı ekran boyutlarına sahip cihazlarda çalıştırırsınız.

Yalnızca belirli cihazlarla çalıştırılacak şekilde belirli testlere 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ı ek açıklamalar oluşturabilirsiniz:

annotation class TestExpandedWidth
annotation class TestCompactWidth

Ayrıca bunları farklı testlerde kullanabilirsiniz:

class MyTestClass {

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

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

}

Ardından, 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ıyorsanız ve emülatörleri CI'da yönetiyorsanız önce doğru emülatörün veya cihazın hazır ve bağlı olduğundan emin olun. Ardından, parametreyi enstrümanlı testleri çalıştırmak için Gradle komutlarından birine iletin:

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

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

Espresso Cihazı

Espresso, Compose veya UI Automator testleri de dahil olmak üzere herhangi bir türde enstrümanlı test kullanarak testlerde emülatörlerde işlem gerçekleştirmek için Espresso Device'ı kullanın. Bu işlemler arasında ekran boyutunu ayarlama veya katlanabilir durumları ya da pozisyonları değiştirme yer alabilir. Örneğin, katlanabilir bir emülatörü kontrol edebilir ve masaüstü moduna ayarlayabilirsiniz. Espresso Device, belirli özelliklerin gerekli olmasını sağlayan 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 şartları karşılaması gerektiğini unutmayın:

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

Filtre testleri

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

RequiresDeviceMode ek açıklaması

RequiresDeviceMode açıklaması, 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 notu, resmi pencere boyutu sınıflarına göre 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ın boyutunu değiştirdiğinizde cihazın yoğunluğunu etkilemezsiniz. Bu nedenle, bir boyut hedef cihaza sığmıyorsa 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şenler için durum geri yüklemeyi test etmek amacıyla kullanılır. Etkinlik yeniden oluşturma, birden fazla senkronizasyon mekanizması içeren karmaşık bir süreç olduğundan bu sayede testler daha hızlı ve güvenilir hale gelir:

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

Window Testing kitaplığı, pencere yönetimiyle ilgili özellikleri (ör. etkinlik yerleştirme veya katlanabilir özellikler) kullanan ya da doğrulayan testler yazmanıza yardımcı olacak yardımcı programlar içerir. Yapı, Google'ın Maven deposu üzerinden kullanılabilir.

Örneğin, FoldingFeature() işlevini kullanarak, Oluşturma önizlemelerinde kullanabileceğiniz özel bir FoldingFeature oluşturabilirsiniz. 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 ekran özelliklerini taklit edebilirsiniz. Aşağıdaki örnekte, ekranın ortasında HALF_OPENED dikey menteşeli bir FoldingFeature simüle edilmekte ve ardından düzenin beklenen düzen olup olmadığı kontrol edilmektedir:

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ülemeler

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 örneği WindowManager projesinde bulabilirsiniz.

Ek kaynaklar

Belgeler

Örnekler

Codelab uygulamaları