Snapshot testi, mevcut ekran durumunun bir önceki test çalıştırmasında kaydedilen referans görüntüyle (snapshot) karşılaştırıldığı otomatik bir kullanıcı arayüzü doğrulama yöntemidir. Herhangi bir görsel farklılık, geliştiricinin onayını gerektiren bir değişiklik olarak kaydedilir. Öğelerin varlığını kontrol eden UI testlerinin aksine, snapshot testleri piksel düzeyindeki değişiklikleri — kaymalar, renk sapmaları ve düzen sorunları — tespit eder. Android Developers, 2024'e göre, snapshot testi, geleneksel UI testleri tarafından gözden kaçırılan görsel regresyonların %30'una kadarını tespit ederek tutarlı bir arayüzün sürdürülmesi için vazgeçilmez bir araç haline gelir.
Önemli Noktalar
Snapshot testi, bir testin UI bileşenini işleyip sonuç görüntüsünü referans olarak kaydettiği ve sonraki çalıştırmalarda mevcut işlemeyi bu referansla karşılaştırdığı bir tekniktir. Görüntüler eşleşirse test geçer. Farklılıklar bulunursa test başarısız olur ve geliştirici, değiştirilen piksellerin vurgulandığı bir fark (diff) görüntüsü alır. Teknik web geliştirmeden (Jest snapshot) ödünç alınmış ve mobil platformlar için uyarlanmıştır.
Snapshot testlerinin temel değeri, beklenmedik görsel değişikliklerin otomatik olarak tespit edilmesidir. Bir geliştirici, genel bir temadaki renk şemasını değiştirebilir ve yanlışlıkla düzinelerce ekranı etkileyebilir. Düğmelerin ve metinlerin varlığını kontrol eden UI testleri bunu fark etmez. Bir snapshot testi, etkilenen her ekrandaki her piksel değişikliğini yakalayarak değişikliğin etkisinin tam bir resmini sağlar.
Mobile DevOps Summit 2023 anketine göre, klasik UI testlerine ek olarak snapshot testi kullanan ekipler, sürümlerdeki görsel kusur sayısını %40 oranında azaltmaktadır. Bu yaklaşım, bir temel bileşenin değiştirilmesinin uygulamanın düzinelerce ekranını etkileyebileceği tasarım sistemleri ve bileşen tabanlı mimarilere sahip projelerde özellikle etkilidir.
Temel fark, doğrulama nesnesinde yatar. UI testleri, arayüz öğelerinin varlığını, durumunu ve davranışını kontrol eder: “düğme görünür”, “metin bir hata mesajı içeriyor”, “basıldığında yeni bir ekran açılır”. Snapshot testleri, tüm görsel görünümü kontrol eder: öğe konumlandırması, kenar boşlukları, renkler, yazı tipleri, gölgeler ve yuvarlatılmış köşeler. Bir snapshot testi “ekran beklendiği gibi görünüyor mu?” sorusuna yanıt verirken, bir UI testi “ekran beklendiği gibi çalışıyor mu?” sorusuna yanıt verir.
Yürütme hızı da farklılık gösterir. UI testleri bir öykünücü veya gerçek cihazda çalışır, tam uygulama yüklemesi gerektirir ve senaryo başına 10 saniyeden bir dakikaya kadar sürer. Paparazzi gibi kütüphaneleri kullanan snapshot testleri, öykünücü başlatmadan sanal ortamda bileşenleri işleyerek test süresini 100–500 milisaniyeye düşürür. Tam bir snapshot testi seti (50–100 ekran), karşılaştırılabilir bir UI testi seti için 30–60 dakika yerine 2–5 dakikada çalıştırılır.
Ancak snapshot testleri UI testlerinin yerini almaz. En uygun strateji bir kombinasyondur: snapshot testleri görsel regresyonu (her ekranın temel durumlarda işlenmesi) kapsarken, UI testleri davranışsal yönleri (tıklama senaryoları, giriş doğrulama, gezinme) kapsar. Bu kombinasyon, minimum CI çalıştırma süresiyle arayüz doğruluğunda %90 güven sağlar.
Android'de ana araçlar Paparazzi ve Shot'tır. Cash App'ten Paparazzi, Layoutlib yerçekimi düzenini kullanarak öykünücü olmadan JVM test ortamında bileşenleri işler. Karumi'den Shot, gerçek bir cihazda veya öykünücüde Instrumentation ekran görüntüleri alır ve AShot kütüphanesi aracılığıyla bunları referanslarla karşılaştırır, çözünürlük ve piksel yoğunluğu farklılıklarını hesaba katar.
Paparazzi öykünücü başlatmayı gerektirmez — işleme, Layoutlib aracılığıyla JVM üzerinde yapılır ve birim testlerine benzer hız sağlar. Kütüphane hem View sistemini hem de Jetpack Compose'u destekler. Compose için paparazzi.snapshot { MyComposable() } değiştiricisini kullanın. Referanslar src/test/snapshots içinde saklanır ve her çalıştırmada otomatik olarak karşılaştırılır. Maksimum fark yüzdesi maxPercentDifference aracılığıyla yapılandırılır.
Point-Free'den SnapshotTesting, yalnızca UIImage değil, aynı zamanda dizeleri, JSON'ı, Data'yı ve tüm Core Data depolarını karşılaştırmayı destekler. Bu, onu yalnızca UI snapshotları için değil, aynı zamanda JSON yanıtlarının serileştirme ve kod çözme doğrulaması için de çok yönlü bir araç haline getirir. SwiftUI için, .image(on: .iPhone13) değiştiricisiyle assertSnapshot uzantısını kullanın. record: true stratejisi ilk çalıştırmada referanslar oluşturur.
React Native için popüler çözüm, jest-image-snapshot ile birleştirilmiş react-native-testing-library'dir. Snapshot testine yönelik web yaklaşımı, bileşenlerin Node.js ortamında işlenmesi ve ardından sanal DOM'un JSON snapshotlarının karşılaştırılmasıyla mobil ortama taşınır. Bu yaklaşım native'den daha hızlıdır ancak daha az doğrudur — platforma özgü yazı tipi işleme ve sistem bileşeni özelliklerini hesaba katmaz. Flutter için, goldens araç seti aracılığıyla golden testi kullanılır.
Android (Paparazzi) ve iOS (SnapshotTesting) için snapshot testlerine bakalım. Her iki örnek de bir bileşenin görünümünü doğrular — avatar, ad ve durum içeren bir kullanıcı kartı. Test, bileşeni işler ve test verileriyle sonucu depoda saklanan bir referans görüntüyle karşılaştırır.
Paparazzi, işlemeyi yakalamak için @Test ek açıklamasını ve snapshot() yöntemini kullanır. Referanslar src/test/snapshots klasöründe saklanır ve karşılaştırma için bir sonraki çalıştırmada otomatik olarak yüklenir.
class UserCardSnapshotTest {
@get:Rule
val paparazzi = Paparazzi(
theme = "Theme.MyApp",
maxPercentDifference = 0.1
)
@Test
fun userCard_defaultState() {
val card = UserCard(
name = "Alice Johnson",
status = "Online",
avatarUrl = "https://example.com/avatar.png"
)
paparazzi.snapshot(card)
}
@Test
fun userCard_offlineState() {
val card = UserCard(
name = "Bob Smith",
status = "Offline",
avatarUrl = null
)
paparazzi.snapshot(card, name = "user_card_offline")
}
}
SnapshotTesting, assertSnapshot içinde .snapshot() değiştiricisini kullanır. Kütüphane biçimi otomatik olarak belirler — UIView için UIImage, metin için String, ikili veriler için Data.
import SnapshotTesting
import XCTest
class UserCardSnapshotTests: XCTestCase {
func testUserCardDefaultState() {
let card = UserCardView(
name: "Alice Johnson",
status: "Online",
avatarURL: URL(string: "https://example.com/avatar.png")
)
let controller = UIHostingController(rootView: card)
assertSnapshot(matching: controller, as: .image(on: .iPhone13))
}
func testUserCardOfflineState() {
let card = UserCardView(
name: "Bob Smith",
status: "Offline",
avatarURL: nil
)
assertSnapshot(matching: card, as: .image(on: .iPhone13))
}
}
Tipik bir iş akışı dört aşamadan oluşur. İlk çalıştırma (kayıt modu): tüm snapshot testleri kayıt modunda çalıştırılır — referans görüntüler oluşturulur ve depoya kaydedilir. Bu aşama, ilk test kurulumu sırasında veya arayüzde bilinçli bir değişiklikten sonra gerçekleştirilir. Kayıttan sonra referanslar, kodla birlikte commit edilir ve projenin bir parçası haline gelir.
Sonraki çalıştırmalarda testler karşılaştırma modunda çalışır: her yeni işleme referansla karşılaştırılır. Farklılıklar bulunursa bir fark (diff) görüntüsü oluşturulur: referansla eşleşen pikseller yeşil, farklı olanlar kırmızı vurgulanır. Geliştirici diff'i inceler ve bir karar verir: değişiklik bekleniyorsa (bilinçli tasarım değişikliği), referans kayıt komutuyla güncellenir; beklenmiyorsa hata düzeltilir. Referans güncelleme tek bir komutla yapılır: Paparazzi için `./gradlew recordPaparazzi`, SnapshotTesting için — `assertSnapshot(record: true)`.
Spotify Engineering Blog (2022)'ye göre, açıklanan iş akışını kullanan ekipler, fark görüntülerini analiz etmek için test başına ortalama 2 dakika harcar. 50 snapshot testi setinde, tam bir referans güncelleme döngüsü 15–20 dakika sürer; bu, 50 ekrandaki görsel değişikliklerin manuel olarak doğrulanmasından önemli ölçüde daha hızlıdır.
Snapshot testlerinin temel sınırlamaları vardır. Ortama duyarlılık: aynı bileşen, farklı işletim sistemi sürümlerinde, ekran yoğunluklarında ve yazı tipi yapılandırmalarında farklı şekilde işlenebilir. Bir makinede oluşturulan referanslar, CI sunucusundaki işlemeden farklı olabilir. Çözüm, sabit ortam parametreleri kullanmaktır: Paparazzi için belirli bir Layoutlib sürümü veya SnapshotTesting için tam bir cihaz modeli.
Anti-kalıp #1: dev snapshotlar — tüm ekranı yakalayan bir snapshot testi, herhangi bir bileşendeki en küçük değişiklikte bile başarısız olur. Doğru yaklaşım, tek tek bileşenleri (düğme, kart, giriş alanı) ayrı ayrı test etmektir. Her bileşen bağımsız olarak test edilir ve değişikliğin kaynağının kesin olarak belirlenmesini sağlar. Anti-kalıp #2: diff'leri yok saymak — fark görüntülerini analiz etmeden referansları otomatik olarak güncellemek, snapshot testlerinin değerini sıfıra indirir. Her diff, geliştiricinin bilinçli bir kararını gerektirir.
Better Engineering Blog (2023)'e göre, snapshot testleri, tasarım sistemi bileşenlerini ve temel durumlardaki (boş, dolu, hata ve sınır) ana ekranları kapsadığında en büyük değeri sağlar. İşlemedeki zaman damgalarının belirleyici olmayan yapısı nedeniyle animasyonları ve dinamik durumları snapshot testleriyle kapsamak verimsizdir — bu tür senaryolar için video kaydı veya manuel QA kontrolü daha uygundur.
Sıkça Sorulan Sorular
Hayır, snapshot testleri görsel görünümü kontrol ederken, UI testleri arayüz davranışını kontrol eder. En uygun strateji her iki yaklaşımı birleştirmektir: görsel regresyon için snapshotlar, senaryolar ve gezinme için UI testleri. Snapshotlar “doğru görünüyor mu?” sorusuna yanıt verir, UI testleri “doğru çalışıyor mu?” sorusuna.
Referanslar, yeni bir tema rengi, değiştirilen kenar boşlukları, öğe ekleme veya çıkarma gibi her bilinçli tasarım değişikliğinde güncellenir. Güncelleme kayıt modu aracılığıyla yapılır ve ardından değişikliklerin tasarımcının beklentilerini karşıladığından emin olmak için kod incelemesinde fark görüntüleri incelenir.
İlk olarak, tasarım sistemi bileşenleri — düğmeler, kartlar, giriş alanları, modal pencereler. Ardından temel durumlardaki ana ekranlar. Snapshotlarla test etmeyin animasyonlar, WebView, haritalar ve dinamik içerikli ekranlar — belirleyici olmama nedeniyle snapshotlar yanlış başarısızlıklar üretir.
Kayıt ve test modları için aynı API seviyesini kullanın. Paparazzi için yapılandırmada belirli bir Layoutlib sürümü belirtin. SnapshotTesting için cihaz modelini sabitleyin. Android 14'te oluşturulan referanslar, sistem yazı tipleri ve Material temasındaki değişiklikler nedeniyle Android 12'deki işlemeden farklı olabilir.
CI'da snapshot testleri doğrulama modunda (verify) çalışır. Bir test başarısız olursa, CI derleme yapıtlarında fark görüntüsünü gösterir. Kayıt modu (referans güncelleme) geliştirici tarafından yerel olarak veya manuel tetiklemeli ayrı bir CI görevinde gerçekleştirilir. Referans görüntüler depoya commit edilmelidir.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun