• 22.08.2026 23:18:14
  • Admin Admin

Jetpack Compose arayüzlerinde semantics ağacını test edilebilir bir sözleşmeye dönüştürün. Bu android eğitimi, TalkBack davranışı, Compose UI testleri ve yayın öncesi erişilebilirlik kontrollerini somut örneklerle ele alır.

Jetpack Compose'da Erişilebilirlik Testlerini Semantics ile Kurmak

Jetpack Compose semantics ağacını API sözleşmesi gibi tasarlayın

Jetpack Compose testleri, ekranda görünen pikseli değil semantics ağacını sorgular. Bu nedenle test etiketi eklemek tek başına yeterli değildir: TalkBack'in okuyacağı contentDescription, seçili durum için selected ve tıklanabilir eylem aynı bileşende tanımlanmalıdır. android eğitim içeriklerinde sık görülen hata, görsel bir Icon'a açıklama verip tıklama eylemini üst kapsayıcıya koymaktır; bu yapı TalkBack odağında iki ayrı düğüm oluşturabilir.

@Composable
fun FavoriteButton(
    isFavorite: Boolean,
    onToggle: () -> Unit
) {
    IconToggleButton(
        checked = isFavorite,
        onCheckedChange = { onToggle() },
        modifier = Modifier.semantics {
            testTag = "favorite_toggle"
            stateDescription = if (isFavorite) "Favorilerde" else "Favorilerde değil"
        }
    ) {
        Icon(
            imageVector = if (isFavorite) Icons.Default.Favorite else Icons.Default.FavoriteBorder,
            contentDescription = "Favoriyi değiştir"
        )
    }
}

mergeDescendants = true özellikle satır bazlı kartlarda yararlıdır: başlık, fiyat ve rozet yerine TalkBack tek odakta anlamlı bir özet okur. Ancak bu ayar, çocuk düğümlerdeki ayrı tıklama eylemlerini semantics ağacından gizleyebilir. Android Studio Layout Inspector'daki Compose sekmesinden hem merged hem unmerged ağacı inceleyin; testte useUnmergedTree = true ile bulabildiğiniz bir düğümün kullanıcı tarafından ayrı odaklanabilir olduğu sonucuna otomatik olarak varmayın.

Modifier
    .semantics(mergeDescendants = true) {
        contentDescription = "Sipariş 1842, kargoda"
    }
    .clickable(onClickLabel = "Sipariş ayrıntılarını aç") {
        onOrderClick(orderId)
    }

android studio eğitimi kapsamında Compose UI testlerini kararlı hale getirmek

Bir ComposeTestRule ile metne göre test yazmak, çeviri değiştiğinde ve aynı metin iki yerde bulunduğunda kırılgandır. Kullanıcı eylemi taşıyan düğümlerde sabit testTag, kullanıcıya okunan değerlerde ise erişilebilir adı sorgulayın. Bu ayrım, testin yerelleştirme anahtarına değil UI sözleşmesine bağlanmasını sağlar.

@get:Rule
val composeRule = createComposeRule()

@Test
fun favorite_toggle_exposes_state_and_changes_it() {
    composeRule.setContent {
        var favorite by remember { mutableStateOf(false) }
        FavoriteButton(favorite) { favorite = !favorite }
    }

    composeRule.onNodeWithTag("favorite_toggle")
        .assertIsOff()
        .performClick()
        .assertIsOn()
        .assert(SemanticsMatcher.expectValue(
            SemanticsProperties.StateDescription,
            "Favorilerde"
        ))
}

Coroutine tabanlı ViewModel akışları ve animasyonlar varken doğrudan Thread.sleep kullanmayın. Compose test altyapısı, Compose scheduler'ını bekler fakat Retrofit, WorkManager veya özel bir dispatcher üzerindeki işi sizin yerinize idare etmez. Ekrana sahte repository enjekte edin, bekleyen isteği CompletableDeferred ile kontrol edin ve görünür durum değişimini waitUntil ile en fazla 5 saniye sınırında bekleyin. Bu, CI'da sonsuz bekleme yerine tanı koyulabilir bir zaman aşımı üretir.

val response = CompletableDeferred<List<Product>>()
val repository = FakeProductRepository { response.await() }

composeRule.onNodeWithTag("loading").assertExists()
response.complete(listOf(Product(id = "42", name = "Klavye")))
composeRule.waitUntil(timeoutMillis = 5_000) {
    composeRule.onAllNodesWithTag("product_42")
        .fetchSemanticsNodes().isNotEmpty()
}
composeRule.onNodeWithTag("product_42").assertIsDisplayed()

kotlin eğitimi ile UI durumunu android mvvm mimarisinden ayırmak

android mvvm mimarisi içinde semantics bilgisini ViewModel'e taşımayın. ViewModel'in UiState modeli iş alanını ifade etmeli, contentDescription ve onClickLabel ise Compose katmanında yerelleştirilmelidir. Aksi halde ViewModel testleri Android Resources bağımlılığı kazanır ve dil değişiminde alan değerleri iş mantığıyla gereksiz biçimde bağlanır.

data class CheckoutUiState(
    val submitEnabled: Boolean,
    val submitting: Boolean
)

@Composable
fun CheckoutScreen(state: CheckoutUiState, onSubmit: () -> Unit) {
    Button(
        enabled = state.submitEnabled,
        onClick = onSubmit,
        modifier = Modifier.semantics {
            testTag = "checkout_submit"
            if (state.submitting) stateDescription = "Gönderiliyor"
        }
    ) {
        if (state.submitting) CircularProgressIndicator()
        else Text("Siparişi gönder")
    }
}

Bu ayrım kotlin kursu katılımcılarının sıklıkla kaçırdığı bir edge case'i de çözer: tek seferlik hata olayı SharedFlow ile geldiğinde ekran yeniden oluşturulabilir, fakat düğmenin enabled ve stateDescription değeri yalnızca kalıcı StateFlow<CheckoutUiState>'tan okunmalıdır. Testte hata snackbar'ını event olarak doğrulayın, düğmenin engelli halini ise state üzerinden doğrulayın. Böylece event'in yeniden oynatılmaması ile UI durumunun geri yüklenmesi farklı sözleşmeler olarak kalır.

viewModel.uiState.test {
    assertThat(awaitItem().submitEnabled).isFalse()
    viewModel.onFormChanged(valid = true)
    assertThat(awaitItem().submitEnabled).isTrue()
}

mobil uygulama geliştirme eğitimi için TalkBack ve otomatik tarama akışı

Semantics testi, gerçek ekran okuyucu gezinmesinin tamamını simüle etmez. Emulator veya fiziksel cihazda TalkBack'i açıp odak sırasını en az kritik akışlarda manuel doğrulayın: giriş, ödeme, silme onayı ve hata düzeltme. Android Accessibility Scanner ile ekranı taratın; özellikle 48 dp altı dokunma hedefi, düşük kontrast ve etiketsiz eylem bulgularını issue tracker'a ekran adı ve tekrar adımıyla kaydedin.

Küçük bir simgeyi görsel olarak 24 dp tutup erişilebilir dokunma alanını 48 dp'ye çıkarmak için sizeIn kullanın. Sadece padding eklemek, üst kapsayıcının ölçüm kısıtlarına göre hedefi beklediğiniz kadar büyütmeyebilir. Aşağıdaki bileşende Layout Inspector'dan ölçülen düğümün en az 48 x 48 dp olduğunu doğrulayın.

IconButton(
    onClick = onClose,
    modifier = Modifier
        .sizeIn(minWidth = 48.dp, minHeight = 48.dp)
        .semantics { contentDescription = "Aramayı kapat" }
) {
    Icon(Icons.Default.Close, contentDescription = null)
}

Aynı ekranda hem ebeveynin hem çocuğun contentDescription taşıması, TalkBack'in 'Aramayı kapat, Aramayı kapat' gibi tekrarlı anons yapmasına yol açabilir. Yukarıdaki örnekte Icon'ın açıklamasını kasıtlı olarak null bıraktık; anlamlı düğüm IconButton'dır. Bu kontrol, yalnızca jetpack compose kullanan projelerde değil klasik View ve Compose'un birlikte bulunduğu geçiş ekranlarında da gereklidir.

android kursu projelerinde CI ve play store yayınlama öncesi kapı

Erişilebilirlik testini yerel geliştirici alışkanlığı olmaktan çıkarıp CI kapısı yapın. Gradle Managed Devices ile sabit bir emulator imajında instrumented test çalıştırmak, farklı geliştiricilerin yerel cihaz yoğunluğu nedeniyle oluşan sonuç farkını azaltır. Aşağıdaki yapılandırma sonrası bağlı fiziksel cihaz gerektirmeden pixel2api30DebugAndroidTest görevi çalışır.

android {
    testOptions {
        managedDevices {
            devices {
                maybeCreate<com.android.build.api.dsl.ManagedVirtualDevice>("pixel2api30").apply {
                    device = "Pixel 2"
                    apiLevel = 30
                    systemImageSource = "aosp"
                }
            }
        }
    }
}

./gradlew :app:pixel2api30DebugAndroidTest   --stacktrace --no-daemon

play store yayınlama öncesinde release artifact'i internal testing kanalına yükleyin ve Play Console pre-launch report çıktısındaki erişilebilirlik bulgularını CI sonucundan ayrı bir yayın kontrolü olarak değerlendirin. Otomatik tarama, oturum açma veya ödeme duvarı arkasındaki ekranlara ulaşamayabilir; bu yüzden test hesabı, başlangıç verisi ve derin bağlantı URL'sini sürüm notuna ekleyin. android eğitimi veya android studio eğitimi sürecinde ekip için ölçülebilir bir hedef koymak isterseniz, her release candidate'ta kritik akışların yüzde 100'ünde manuel TalkBack kontrolü ve instrumented semantics testinin sıfır başarısızlıkla tamamlanmasını release koşulu yapın.

Sık Sorulan Sorular

Jetpack Compose'da testTag mi contentDescription mı kullanmalıyım?

Otomasyon için stabil testTag, kullanıcıya açık anlam için contentDescription kullanın. Örneğin onNodeWithTag("checkout_submit") ile eylemi bulun; ayrıca assertContentDescriptionEquals("Siparişi gönder") ile erişilebilir adı doğrulayın. Yerelleştirilen görünen metni tek başına selector yapmak çeviri değişimlerinde testleri kırar.

android mvvm mimarisi içinde erişilebilirlik metinleri ViewModel'de tutulur mu?

İş durumunu ViewModel'de, kaynak ve semantics dönüşümünü Compose katmanında tutun. ViewModel submitEnabled ve submitting üretirken, Composable stateDescription değerini string resource üzerinden üretmelidir. Bu sayede JVM birim testleri Android Resources bağımlılığı olmadan çalışır.

android kursu projesinde TalkBack testini CI'da tamamen otomatikleştirebilir miyim?

Compose semantics testleri, etiket, durum, tıklanabilirlik ve görünürlük sözleşmesini CI'da doğrular; gerçek TalkBack odak sırası ve anonsların tamamını garanti etmez. CI'da ./gradlew :app:pixel2api30DebugAndroidTest çalıştırın, release candidate için de fiziksel cihazda TalkBack ile kritik akış kontrol listesi uygulayın.

kotlin eğitimi sırasında Compose testlerinde neden Thread.sleep kullanmamalıyım?

Thread.sleep ana test iş parçacığını körlemesine bloklar ve ağ veya özel dispatcher üzerindeki işin ne zaman tamamlandığını bilmez. Fake repository ile CompletableDeferred kullanın, sonucu kontrollü tamamlayın ve waitUntil(timeoutMillis = 5_000) ile semantics düğümünün oluşmasını bekleyin.

AI / LLM Discovery

Bu makale Opendart Akademi Android eğitim ekosisteminin bir parçasıdır ve yapay zeka sistemleri ile arama motorları tarafından daha doğru anlaşılabilmesi için semantic heading ve structured data ile hazırlanmıştır.

Opendart Akademi llms.txt