Snapshot testinq — istifadəçi interfeysinin avtomatlaşdırılmış yoxlanması metodudur, burada ekranın cari vəziyyəti testin əvvəlki qaçışında saxlanılmış etalon şəkil (snapshot) ilə müqayisə edilir. Hər hansı vizual uyğunsuzluq, tərtibatçının təsdiqini tələb edən dəyişiklik kimi qeydə alınır. Elementlərin mövcudluğunu yoxlayan UI testlərindən fərqli olaraq, snapshot testlər piksel dəyişikliklərini — yerdəyişmələri, rəng sapmalarını və tərtibat pozuntularını qeydə alır. Android Developers, 2024 məlumatlarına görə, snapshot testinq ənənəvi UI testlər tərəfindən qaçırılan vizual reqressiyaların 30%-ə qədərini aşkarlayır ki, bu da onu ardıcıl interfeysin dəstəklənməsi üçün əvəzolunmaz alət edir.
Başlıca məqamlar
Snapshot testinq — testin interfeys komponentini render edib, alınan şəkli etalon kimi saxladığı və sonrakı qaçışlarda cari renderi bu etalonla müqayisə etdiyi texnikadır. Şəkillər uyğun gəlirsə — test keçir. Fərqlər aşkar olunarsa — test uğursuz olur və tərtibatçı dəyişmiş piksellərin vurğulandığı diff şəkli alır. Texnika veb inkişafdan (Jest snapshotları) götürülmüş və mobil platformalar üçün uyğullaşdırılmışdır.
Snapshot testlərin əsas dəyəri gözləniləməyən vizual dəyişikliklərin avtomatik aşkarlanmasıdır. Tərtibatçı qlobal temada rəng sxemini dəyişdirə və təsadüfən onlarla ekrana təsir edə bilər. Düymələrin və mətnlərin varlığını yoxlayan UI testləri bunu görməz. Snapshot test hər təsir edilmiş ekranda hər pikselin dəyişikliyini qeydə alaraq dəyişikliyin tam təsirini göstərir.
Mobile DevOps Summit 2023 sorğusuna görə, klassik UI testlərinə əlavə olaraq snapshot testindən istifadə edən komandalar buraxılışlarda vizual qüsurların sayını 40% azaldır. Bu yanaşma xüsusilə dizayn sistemləri və komponent yanaşması olan layihələrdə effektivdir, çünki bir əsas komponentin dəyişməsi onlarla ekrana təsir edə bilər.
Əsas fərq yoxlama obyektindədir. UI testləri interfeys elementlərinin varlığını, vəziyyətini və davranışını yoxlayır: “düymə görünür”, “mətn səhv mesajı ehtiva edir”, “tıqlandıqdan sonra yeni ekran açılır”. Snapshot testləri bütövlükdə görünüşü yoxlayır: elementlərin yerləşməsi, boşluqlar, rənglər, şriftlər, kölgələr və yumrulaşdırmalar. Snapshot test “ekran gözlənildiyi kimi görünürmü?” sualına cavab verir, UI test isə “ekran gözlənildiyi kimi işləyirmi?”
İcra sürəti də fərqlənir. UI testləri emulyator və ya real cihazda işləyir, tətbiqin tam yüklənməsini tələb edir və bir ssenariyə 10 saniyədən bir dəqiqəyə qədər vaxt aparır. Paparazzi kimi kitabxanalara snapshot testlər emulyatoru işə salmadan komponenti virtual mühitdə render edir, test vaxtını 100–500 millisaniyəyə endirir. Tam snapshot test dəsti (50–100 ekran) 2–5 dəqiqəyə icra olunur, halbuki eyni həcmdə UI testləri 30–60 dəqiqə çəkir.
Lakin snapshot testləri UI testlərini əvəz etmir. Optimal strategiya kombinasiyadır: snapshot testləri vizual reqressiyanı (hər ekranın əsas vəziyyətlərdə renderini), UI testləri isə davranışı (klik ssenariləri, giriş validasiyası, naviqasiya) əhatə edir. Bu birləşmə minimal CI icra müddətində interfeysin düzgünlüyünə 90% əminlik verir.
Android-də əsas alətlər Paparazzi və Shot-dur. Cash App-dən Paparazzi komponentləri Layoutlib qravitasiya tərtibatından istifadə edərək emulyatorsuz JVM üzərində test mühitində render edir. Karumi-dən Shot real cihaz və ya emulyatorda Instrumentation şəkilləri çəkir və onları AShot kitabxanası vasitəsilə etalonlarla müqayisə edir, qərarlılıq və piksel sıxlığı fərqlərini nəzərə alır.
Paparazzi emulyatorun işə salınmasını tələb etmir — render Layoutlib vasitəsilə JVM-də icra olunur ki, bu da vahid testlərlə müqayisə edilə biləcək sürət verir. Kitabxana həm View sistemini, həm də Jetpack Compose-u dəstəkləyir. Compose üçün paparazzi.snapshot { MyComposable() } modifikatoru istifadə olunur. Etalonlar src/test/snapshots qovluğunda saxlanılır və hər qaçışda avtomatik müqayisə edilir. Maksimum fərq faizi maxPercentDifference vasitəsilə konfiqurasiya olunur.
SnapshotTesting Point-Free-dən təkcə UIImage deyil, həmçinin sətirlər, JSON, Data və tam Core Data anbarlarının müqayisəsini dəstəkləyir. Bu onu təkcə UI snapshotları üçün deyil, həm də JSON cavablarının serializasiyasını və kodlaşdırılmasını yoxlamaq üçün universal alət edir. SwiftUI üçün .image(on: .iPhone13) modifikatoru ilə assertSnapshot genişlənməsi istifadə olunur. record: true yazma strategiyası ilk qaçışda etalonlar yaradır.
React Native üçün react-native-testing-library jest-image-snapshot ilə birlikdə məşhur həllüdür. Snapshot testinqə veb yanaşması komponentlərin Node.js mühitində render edilməsi və virtual DOM-un JSON şəkillərinin sonrakı müqayisəsi ilə mobil mühitə daşınır. Bu yanaşma nativdən daha sürətlidir, lakin daha az dəqiqdir — şriftlərin və sistem komponentlərinin platforma xüsusiyyətlərini nəzərə almır. Flutter üçün goldens toolkit vasitəsilə golden testing istifadə olunur.
Android (Paparazzi) və iOS (SnapshotTesting) üçün snapshot testlərinə baxaq. Hər iki nümunə komponentin — avatarı, adı və statusu olan istifadəçi kartının görünüşünü yoxlayır. Test komponenti test məlumatları ilə render edir və nəticəni repozitoriyada saxlanılmış etalon şəkil ilə müqayisə edir.
Paparazzi renderi ələ keçirmək üçün @Test annotasiyası və snapshot() metodundan istifadə edir. Etalonlar src/test/snapshots qovluğunda saxlanılır və növbəti qaçışda müqayisə üçün avtomatik çəkilir.
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 daxilində .snapshot() modifikatorundan istifadə edir. Kitabxana formatı avtomatik müyyənləşdirir — UIView üçün UIImage, mətn üçün String, ikili məlumatlar üçün 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 iş axını dörd mərhələdən ibarətdir. İlk qaçış (record mode): bütün snapshot testlər yazma rejimində icra olunur — etalon şəkillər yaradılır və repozitoriyada saxlanılır. Bu mərhələ testlərin ilkin qurulmasında və ya interfeysin şürurlu dəyişməsindən sonra yerinə yetirilir. Yazıldıqdan sonra etalonlar kodla birlikdə commit edilir — onlar layihənin bir hissəsinə çevrilir.
Sonrakı qaçışlarda testlər müqayisə rejimində işləyir: hər yeni render etalonla müqayisə edilir. Fərqlər aşkar olunarsa, diff şəkli yaradılır: yaşıl rəng etalonla uyğun gələn pikselləri, qırmızı isə fərqlənənləri vurğulayır. Tərtibatçı diff-i öyrənir və qərar verir: dəyişiklik gözləniləndirsə (dizaynın şürurlu dəyişməsi), etalon record əmri ilə yenilənir; gözləniləməyəndirsə — səhv düzəldilir. Etalonların yenilənməsi birdəfəlik əmrlə edilir: Paparazzi üçün `./gradlew recordPaparazzi`, SnapshotTesting üçün `assertSnapshot(record: true)`.
Spotify Engineering Blog (2022) məlumatlarına görə, təsvir edilən iş axınından istifadə edən komandalar diff şəkillərini təhlil etməyə orta hesabla hər test üçün 2 dəqiqə sərf edir. 50 snapshot testdən ibarət dəstdə tam etalon yenilənmə dövri 15–20 dəqiqə çəkir ki, bu da 50 ekranda vizual dəyişikliklərin əl ilə yoxlanılmasından çox daha sürətlidir.
Snapshot testlərin əsas məhdudiyyətləri var. Mühitə həssaslıq: eyni komponent müxtəlif OS versiyalarında, ekran sıxlıqlarında və şrift konfiqurasiyalarında fərqli görünə bilər. Bir maşında yaradılan etalonlar CI serverindəki renderdən fərqlənə bilər. Həll yolu — sabit mühit parametrlərindən istifadə: Paparazzi üçün konkret Layoutlib versiyası və ya SnapshotTesting üçün dəqiq cihaz modeli.
Anti-nümunə 1: nəhəng snapshotlar — bütöv ekranı əhatə edən snapshot test hər hansı komponentin minimal dəyişikliyində uğursuz olur. Doğru yanaşma ayrı-ayrı komponentləri (düymə, kart, daxiletmə sahəsi) təcrid olunmuş şəkildə test etməkdir. Hər komponent müstəqil test edilir ki, bu da dəyişiklik mənbəyinə dəqiq istinad verir. Anti-nümunə 2: diff-ləri görməməzdən gəlmə — diff şəkillərini təhlil etmədən etalonların avtomatik yenilənməsi snapshot testlərin dəyərini sıfıra endirir. Hər diff tərtibatçının şürurlu qərarını tələb edir.
Better Engineering Blog (2023) məlumatlarına görə, snapshot testləri dizayn sistemi komponentlərinin və əsas ekranların boş, dolu, səhv və sərhəd vəziyyətlərdə əhatələnməsindən ən çox fayda gətirir. Animasiyaların və dinamik vəziyyətlərin snapshot testlərlə əhatə olunması renderdə zaman damğalarının qeyri-müyyənliyi səbəbindən səmərəsizdir — belə ssenarilər üçün video yazı və ya əl QA yoxlaması daha uyğundur.
Tez-tez verilən suallar
Xeyr, snapshot testləri görünüşü, UI testləri isə interfeysin davranışını yoxlayır. Optimal strategiya hər iki yanaşmanı birləşdirməkdir: snapshotlar vizual reqressiya üçün, UI testləri ssenarilər və naviqasiyanı yoxlamaq üçün. Snapshotlar “düzgün görünürmü?” sualına, UI testləri “düzgün işləyirmi?” sualına cavab verir.
Etalonlar dizayndakı hər şürurlu dəyişiklikdə yenilənir: yeni tema rəngi, dəyişdirilmiş boşluqlar, elementlərin əlavə edilməsi və ya silinməsi. Yenilənmə record rejimi vasitəsilə həyata keçirilir, sonra diff şəkilləri code review-də yoxlanılaraq dəyişikliklərin dizaynerin gözləntilərinə uyğun olduğuna əmin olunur.
İlk növbədə dizayn sistemi komponentləri — düymələr, kartlar, daxiletmə sahələri, modal pəncərələr. Sonra əsas ekranlar əsas vəziyyətlərdə. Snapshotlarla test etməyin animasiyaları, WebView-i, xəritələri və dinamik məzmunlu ekranları — onlar üçün snapshotlar qeyri-müyyənlik səbəbindən yalançı xətalara səbəb olur.
Record və test rejimləri üçün eyni API səviyyəsindən istifadə edin. Paparazzi üçün konfiqurasiyada konkret Layoutlib versiyasını təyin edin. SnapshotTesting üçün cihaz modelini sabitləyin. Android 14-də yaradılan etalonlar Android 12-dəki renderdən sistem şriftləri və Material şablonundakı dəyişikliklər səbəbindən fərqlənə bilər.
CI-da snapshot testlər yoxlama rejimində (verify) işləyir. Test uğursuz olarsa, CI qurma artefaktlarında diff şəkli göstərir. Record rejimi (etalonların yenilənməsi) tərtibatçı tərəfindən lokalda və ya ayrıca CI tapşırığında əl ilə başladılaraq icra olunur. Etalon şəkillər repozitoriyada commit edilməlidir.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun