Coroutine yürütme üzerinde daha fazla kontrol sağlamak için Compose test API'lerinin (createComposeRule,
createAndroidComposeRule, runComposeUiTest,
runAndroidComposeUiTest vb.) v2 sürümleri kullanıma sunuldu. Bu güncelleme, API yüzeyinin tamamını kopyalamaz. Yalnızca test ortamını oluşturan API'ler güncellenmiştir.
v1 API'leri kullanımdan kaldırıldı. Yeni API'lere geçiş yapmanız önemle tavsiye edilir. Taşıma işlemi, testlerinizin standart eş yordam davranışıyla uyumlu olduğunu doğrular ve gelecekteki uyumluluk sorunlarını önler. Desteği sonlandırılan v1 API'lerinin listesi için API eşlemeleri başlıklı makaleyi inceleyin.
Bu değişiklikler androidx.compose.ui:ui-test-junit4:1.11.0-alpha03+ ve androidx.compose.ui:ui-test:1.11.0-alpha03+'de yer almaktadır.
v1 API'leri UnconfinedTestDispatcher kullanırken v2 API'leri, çalışan kompozisyon için varsayılan olarak StandardTestDispatcher kullanır. Bu değişiklik, Compose test davranışını standart runTest API'leriyle uyumlu hale getirir ve eş yordam yürütme sırası üzerinde açık kontrol sağlar.
Test ortamını yapılandırma
Compose test v2 API'leri, test ortamını özelleştirmek için ComposeUiTestConfig kullanır. Testler için kurulum işlevleri oluşturan API'ler (ör. createComposeRule, runComposeUiTest ve diğer ilgili API'ler) ComposeUiTestConfig kabul eder. Bu yapılandırma nesnesi, effectContext, runTestContext ve testTimeout gibi çevreyle ilgili API'leri tek bir nesnede birleştirir.
Yapılandırma modeli inputMode öğesini de yönetir. Compose test v2 API'leri, determinizmi sağlamak ve giriş modu durumunun testler arasında sızmasını önlemek için her testin başında varsayılan olarak InputMode.Touch'yi zorunlu kılar.
ComposeUiTestConfig, varsayılan olarak StandardTestDispatcher kullanan Compose Test v2 API'lerinin bir parçasıdır. Testlerinizde v1 API'leri kullanılıyorsa v2 test API'lerine geçiş başlıklı makaleyi inceleyin
ComposeUiTestConfig.
ComposeUiTestConfig'e taşıma
Testlerde kurulum işlevleri oluşturmaya yönelik aşırı yüklemeler arasında, effectContext, runTestContext veya testTimeout gibi ayrı yapılandırma parametrelerini kabul eden çeşitli aşırı yüklemeler kullanımdan kaldırıldı. Testlerinizi aşağıdaki örnekte gösterildiği gibi ComposeUiTestConfig kullanacak şekilde güncelleyin:
val testConfig = ComposeUiTestConfig( effectContext = EmptyCoroutineContext, runTestContext = EmptyCoroutineContext, testTimeout = 30.seconds ) @get:Rule val rule = createComposeRule(config = testConfig) // OR runComposeUiTest(config = testConfig) {}
Varsayılan giriş modu
Testler, test başlamadan önce enstrümantasyon API'leri aracılığıyla yapılandırılan dokunma dışı giriş modlarına bağlıysa taşıma sırasında başarısız olabilir. Testler için kurulum işlevlerinde, sistem daha fazla determinizm sağlamak ve durum sızıntısını önlemek için her testin başında varsayılan olarak InputMode.Touch'yı zorunlu kılar. Bu, ortam cihazı durumunu ve test öncesi kurulumu geçersiz kılar.
Bu sorunu çözmek için ComposeUiTestConfig bölümünde gerekli giriş modunu belirtin:
class FocusTest { @get:Rule val rule = createComposeRule( config = ComposeUiTestConfig(inputMode = InputMode.Keyboard) ) @Test fun testFocus() {} }
Giriş modunu tüm test sınıfı yerine tek tek test senaryoları için yapılandırmak üzere ComposeUiTestConfig değerini runComposeUiTest değerine iletin:
class FocusTest { @Test fun testTouchMode() = runComposeUiTest { // Runs with the default InputMode.Touch } @Test fun testKeyboardMode() = runComposeUiTest( ComposeUiTestConfig(inputMode = InputMode.Keyboard) ) { // Runs with InputMode.Keyboard } }
Diğer taşıma sorunları ve çözümleri için Sık karşılaşılan hatalar ve bunları düzeltme başlıklı makaleyi inceleyin.
v2 test API'lerine geçiş yapma
v2 API'lerine yükseltirken paket içe aktarmalarını güncellemek ve yeni dağıtıcı değişikliklerini uygulamak için genellikle Bul + Değiştir'i kullanabilirsiniz.
Alternatif olarak, aşağıdaki istemle Gemini'dan Compose test API'lerinin 2. sürümüne geçiş yapmasını isteyin:
Yapay zeka istemi
v1 test API'lerinden v2 test API'lerine geçiş
Bu istem, v2 test API'lerine geçiş yapmak için bu kılavuzu kullanır.
Migrate to Compose testing v2 APIs using the official
migration guide.Kullanımdan kaldırılan v1 API'lerini v2 sürümleriyle eşlemek için aşağıdaki tabloyu kullanın:
Kullanımdan kaldırıldı (v1) |
Değiştirme (v2) |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Geriye dönük uyumluluk ve istisnalar
Mevcut v1 API'lerin desteği sonlandırıldı ancak mevcut davranışı korumak ve değişikliklerin bozulmasını önlemek için UnconfinedTestDispatcher kullanmaya devam edin.
Varsayılan davranışın değiştiği tek istisna aşağıda verilmiştir:
AndroidComposeUiTestEnvironment sınıfında kompozisyon çalıştırmak için kullanılan varsayılan test dağıtıcı, UnconfinedTestDispatcher yerine StandardTestDispatcher olarak değiştirildi. Bu durum, oluşturucuyu kullanarak bir örnek oluşturduğunuz veya AndroidComposeUiTestEnvironment alt sınıfını oluşturup bu oluşturucuyu çağırdığınız durumları etkiler.
Önemli değişiklik: Eş yordam yürütme üzerindeki etki
API'lerin v1 ve v2 sürümleri arasındaki temel fark, eşzamanlı rutinlerin gönderilme şeklidir:
- v1 API'leri (
UnconfinedTestDispatcher): Bir eş yordam başlatıldığında mevcut iş parçacığında hemen yürütülür ve genellikle test kodunun bir sonraki satırı çalıştırılmadan önce tamamlanırdı. Üretim davranışının aksine, bu anında yürütme, canlı bir uygulamada meydana gelecek gerçek zamanlama sorunlarını veya yarış durumlarını istemeden maskeleyebilir. - v2 API'leri (
StandardTestDispatcher): Bir eş yordam başlatıldığında sıraya alınır ve test, sanal saati açıkça ilerletene kadar yürütülmez. Standart Compose test API'leri (ör.waitForIdle()) bu senkronizasyonu zaten işlediğinden bu standart API'leri kullanan çoğu test, herhangi bir değişiklik yapılmadan çalışmaya devam edecektir.
Sık karşılaşılan hatalar ve bunları düzeltme
v2'ye yükselttikten sonra testleriniz başarısız olursa büyük olasılıkla aşağıdaki kalıbı gösterirler:
- Başarısızlık: Bir görevi başlatırsınız (örneğin, ViewModel verileri yükler) ancak veriler hâlâ "Yükleniyor" durumunda olduğundan onayınız hemen başarısız olur.
- Neden: v2 API'lerde eş yordamlar hemen yürütülmek yerine sıraya alınır. Görev sıraya alındı ancak sonuç kontrol edilmeden önce hiç çalıştırılmadı.
- Düzeltme: Zamanı açıkça ilerletin. Çalışmanın ne zaman yürütüleceğini v2 dağıtıcıya açıkça söylemeniz gerekir.
Önceki yaklaşım
v1'de görev hemen başlatılıp tamamlanıyordu. v2'de aşağıdaki kod, loadData() henüz çalıştırılmadığı için başarısız olur.
// In v1, this launched and finished immediately.
viewModel.loadData()
// In v2, this fails because loadData() hasn't actually run yet!
assertEquals(Success, viewModel.state.value)
Önerilen yaklaşım
Sıraya alınmış görevleri onaylamadan önce yürütmek için waitForIdle veya runOnIdle kullanın.
1. seçenek: waitForIdle kullanıldığında, kullanıcı arayüzü boşta kalana kadar saat ilerletilir ve bu sayede eş yordamın çalıştığı doğrulanır.
viewModel.loadData()
// Explicitly run all queued tasks
composeTestRule.waitForIdle()
assertEquals(Success, viewModel.state.value)
2. seçenek: runOnIdle kullanıldığında, kullanıcı arayüzü boşta kaldıktan sonra kod bloğu kullanıcı arayüzü iş parçacığında yürütülür.
viewModel.loadData()
// Run the assertion after the UI is idle
composeTestRule.runOnIdle {
assertEquals(Success, viewModel.state.value)
}
Manuel senkronizasyon
Otomatik ilerleme devre dışı bırakıldığında olduğu gibi manuel senkronizasyonun söz konusu olduğu senaryolarda, test saati duraklatıldığı için bir eş yordamın başlatılması hemen yürütülmeyle sonuçlanmaz. Sanal saati ilerletmeden sıradaki eş yordamları yürütmek için runCurrent() API'sini kullanın. Bu, geçerli sanal zaman için planlanan görevleri çalıştırır.
composeTestRule.mainClock.scheduler.runCurrent()
waitForIdle(), test saatini kullanıcı arayüzü sabitlenene kadar ilerletirken runCurrent(), mevcut sanal zamanı koruyarak bekleyen görevleri yürütür. Bu davranış, saat boşta durma durumuna getirildiğinde atlanacak olan ara durumların doğrulanmasını sağlar.
Test ortamında kullanılan temel test planlayıcı kullanıma sunulur. Bu planlayıcı, test saatini senkronize etmek için Kotlin runTest API'siyle birlikte kullanılabilir.
runComposeUiTest'e taşıma
Kotlin runTest API'si ile birlikte Compose test API'lerini kullanıyorsanız runComposeUiTest'ye geçmeniz önemle tavsiye edilir.
Önceki yaklaşım
createComposeRule ile runTest'ı birlikte kullanmak iki ayrı saat oluşturur: biri Compose, diğeri ise test coroutine kapsamı için. Bu yapılandırma, test planlayıcıyı manuel olarak senkronize etmenize neden olabilir.
@get:Rule val composeTestRule = createComposeRule() @Test fun testWithCoroutines() { composeTestRule.setContent { var status by remember { mutableStateOf("Loading...") } LaunchedEffect(Unit) { delay(1000) status = "Done!" } Text(text = status) } // NOT RECOMMENDED // Fails: runTest creates a new, separate scheduler. // Advancing time here does NOT advance the compose clock. // To fix this without migrating, you would need to share the scheduler // by passing 'composeTestRule.mainClock.scheduler' to runTest. runTest { composeTestRule.onNodeWithText("Loading...").assertIsDisplayed() advanceTimeBy(1000) composeTestRule.onNodeWithText("Done!").assertIsDisplayed() } }
Önerilen yaklaşım
runComposeUiTest API, test bloğunuzu kendi runTest kapsamında otomatik olarak yürütür. Test saati, Compose ortamıyla senkronize edildiğinden artık planlayıcıyı manuel olarak yönetmeniz gerekmez.
@Test fun testWithCoroutines() = runComposeUiTest { setContent { var status by remember { mutableStateOf("Loading...") } LaunchedEffect(Unit) { delay(1000) status = "Done!" } Text(text = status) } onNodeWithText("Loading...").assertIsDisplayed() mainClock.advanceTimeBy(1000 + 16 /* Frame buffer */) onNodeWithText("Done!").assertIsDisplayed() } }