Eş yordam yürütme üzerinde daha fazla kontrol sağlamak için Compose test API'lerinin v2 sürümleri (createComposeRule, createAndroidComposeRule, runComposeUiTest, runAndroidComposeUiTest vb.) 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ılmıştır ve yeni API'lere geçmeniz ö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'lerin listesi için API eşlemeleri başlıklı makaleyi inceleyin.
v1 API'leri UnconfinedTestDispatcher'e dayanırken v2 API'leri, çalışan oluşturma için varsayılan olarak StandardTestDispatcher'i 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. createComposeRule, runComposeUiTest ve diğer ilgili API'ler gibi testler için kurulum işlevleri oluşturan 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'ı da 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'ler kullanılıyorsa ComposeUiTestConfig kullanmaya başlamadan önce v2 test API'lerine geçiş bölümünü inceleyin.
ComposeUiTestConfig alanına taşıma
Testlerde kurulum işlevleri oluşturmak için kullanılan aşırı yüklemeler arasında, effectContext, runTestContext veya testTimeout gibi bağımsız yapılandırma parametrelerini kabul eden birkaç aşırı yükleme 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 araç API'leri aracılığıyla yapılandırılan dokunmatik olmayan giriş modlarına dayanıyorsa taşıma sırasında başarısız olabilir. Testler için kurulum işlevlerinde sistem, daha fazla belirlilik sağlamak ve durum sızıntısını önlemek amacıyla her testin başında varsayılan olarak InputMode.Touch uygular. Bu işlem, ortam cihaz durumunu ve test öncesi kurulumu geçersiz kılar.
Bu sorunu çözmek için ComposeUiTestConfig içinde 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 ayrı test durumları için yapılandırmak istiyorsanız ComposeUiTestConfig değerini runComposeUiTest öğesine 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ş
v2 API'lere yükseltme yaparken paket içe aktarma işlemlerini güncellemek ve yeni dağıtıcı değişikliklerini uygulamak için genellikle Bul ve Değiştir'i kullanabilirsiniz.
Alternatif olarak, Gemini'dan aşağıdaki istemi kullanarak Compose test API'lerinin 2. sürümüne geçiş yapmasını isteyin:
Yapay Zeka İstemi
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.Desteği sonlandırılan v1 API'leri v2'deki karşılıklarıyla eşlemek için aşağıdaki tabloyu kullanın:
Desteği sonlandırıldı (v1) |
Değiştirme (v2) |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Geriye dönük uyumluluk ve istisnalar
Mevcut v1 API'ler artık kullanımdan kaldırılmıştır ancak mevcut davranışı korumak ve zarar veren değişiklikleri önlemek için UnconfinedTestDispatcher kullanmaya devam edin.
Varsayılan davranışın değiştiği tek istisna şudur:
AndroidComposeUiTestEnvironment sınıfında oluşturma işlemini çalıştırmak için kullanılan varsayılan test dağıtıcısı, 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 etkisi
API'lerin v1 ve v2 sürümleri arasındaki temel fark, eş yordamların nasıl gönderildiğidir:
- 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 gelebilecek gerçek zamanlama sorunlarını veya yarışma durumlarını yanlışlıkla 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 gerçekleştirdiğinden, bu standart API'leri kullanan çoğu test herhangi bir değişiklik yapılmadan çalışmaya devam eder.
Sık karşılaşılan hatalar ve bunları düzeltme
Testleriniz 2. sürüme yükselttikten sonra başarısız olursa muhtemelen aşağıdaki kalıbı gösterir:
- Başarısızlık: Bir görev başlatırsınız (örneğin, bir ViewModel veri yükler) ancak veriler hâlâ "Yükleniyor" durumunda olduğu için onayınız hemen başarısız olur.
- Nedeni: 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. V2 dağıtıcısına işin ne zaman yürütüleceğini açıkça belirtmeniz gerekir.
Önceki yaklaşım
v1'de görev hemen başlatılıp tamamlanıyordu. 2. sürümde, loadData() henüz çalıştırılmadığı için aşağıdaki kod 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
Onaylamadan önce sıraya alınmış görevleri 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 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 kullanıcı arayüzü iş parçacığında kod bloğu 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 ilerlemenin devre dışı bırakılması gibi manuel senkronizasyonun söz konusu olduğu senaryolarda, test saati duraklatıldığı için eş yordamın başlatılması hemen yürütülmesine neden olmaz. 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()
Kullanıcı arayüzü kararlı hale gelene kadar test saatini ilerleten waitForIdle() yönteminin aksine, runCurrent() yöntemi mevcut sanal zamanı korurken beklemedeki görevleri yürütür. Bu davranış, saat boşta durumuna ilerletildiğinde atlanacak ara durumların doğrulanmasını sağlar.
Test ortamında kullanılan temel test planlayıcı gösterilir. Bu programlayıcı, test saatini senkronize etmek için Kotlin runTest API ile birlikte kullanılabilir.
runComposeUiTest alanına taşıma
Kotlin runTest API'si ile birlikte Compose test API'lerini kullanıyorsanız runComposeUiTest'e geçmeniz önemle tavsiye edilir.
Önceki yaklaşım
createComposeRule ile runTest birlikte kullanıldığında iki ayrı saat oluşturulur: biri Compose için, diğeri ise test eş yordam kapsamı için. Bu yapılandırma, test planlayıcıyı manuel olarak senkronize etmenizi gerektirebilir.
@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'si, test bloğunuzu kendi runTest kapsamında otomatik olarak yürütür. Test saati, Compose ortamıyla senkronize edildiğinden artık zamanlayı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() } }