Ang snapshot testing ay isang paraan ng awtomatikong pagsusuri ng user interface, kung saan ang kasalukuyang estado ng screen ay inihahambing sa isang reference na imahe (snapshot) na nai-save sa nakaraang pagtakbo ng test. Anumang visual na pagkakaiba ay itinatala bilang isang pagbabago na nangangailangan ng kumpirmasyon ng developer. Hindi tulad ng UI tests na sinusuri ang presensya ng mga elemento, ang snapshot tests ay nagtatala ng mga pagbabago sa pixel — paglilipat, paglihis ng kulay at mga paglabag sa layout. Ayon sa Android Developers, 2024, ang snapshot testing ay nakakatuklas ng hanggang 30% ng visual regressions na hindi nakuha ng tradisyonal na UI tests, na ginagawa itong isang kailangang-kailangan na tool para sa pagpapanatili ng pare-parehong interface.
Mga Pangunahing Punto
Snapshot testing ay isang technique kung saan ang test ay nagre-render ng isang interface component, nagsi-save ng nakuhang imahe bilang reference, at sa mga susunod na pagtakbo ay inihahambing ang kasalukuyang render sa reference na ito. Kung magkatugma ang mga imahe — pumasa ang test. Kung may nakitang pagkakaiba — nabigo ang test, at ang developer ay makakatanggap ng diff image na may naka-highlight na nagbagong pixels. Ang technique ay hinango mula sa web development (Jest snapshots) at inangkop para sa mobile platforms.
Ang pangunahing halaga ng snapshot tests ay awtomatikong pagtuklas ng hindi inaasahang visual na pagbabago. Ang developer ay maaaring magpalit ng color scheme sa global theme at aksidenteng makaapekto sa dose-dosenang screen. Ang UI tests na sumusuri sa presensya ng mga button at text ay hindi mapapansin ito. Ang snapshot test ay magtatala ng pagbabago ng bawat pixel sa bawat apektadong screen, na nagbibigay ng kumpletong larawan ng epekto ng pagbabago.
Ayon sa survey ng Mobile DevOps Summit 2023, ang mga team na gumagamit ng snapshot testing bilang karagdagan sa klasikong UI tests ay nagbabawas ng bilang ng visual defects sa releases ng 40%. Ang approach na ito ay lalong epektibo sa mga proyekto na may design system at component-based approach, kung saan ang pagbabago ng isang base component ay maaaring makaapekto sa dose-dosenang screen ng application.
Ang pangunahing pagkakaiba ay nasa object ng pagsusuri. UI tests ay sumusuri sa presensya, estado at pag-uugali ng mga elemento ng interface: “kitang-kita ang button”, “naglalaman ng error message ang text”, “pagkatapos ng click ay bubukas ang bagong screen”. Ang snapshot tests ay sumusuri sa kabuuang hitsura: paglalagay ng mga elemento, distansya, kulay, font, anino at pagbilog. Snapshot test ay sumasagot sa tanong na “mukha bang inaasahan ang screen?”, samantalang ang UI test ay “gumagana ba ang screen ayon sa inaasahan?”
Ang bilis ng execution ay magkaiba rin. Ang UI tests ay tumatakbo sa emulator o totoong device, nangangailangan ng buong pag-load ng application at tumatagal mula 10 segundo hanggang isang minuto bawat scenario. Snapshot tests batay sa mga library tulad ng Paparazzi ay nagre-render ng component sa virtual na kapaligiran nang hindi pinapatakbo ang emulator, na nagbabawas ng oras ng test sa 100–500 millisecond. Ang isang buong set ng snapshot tests (50–100 screen) ay naisasagawa sa 2–5 minuto, sa halip na 30–60 minuto para sa katulad na set ng UI tests.
Gayunpaman, hindi pinapalitan ng snapshot tests ang UI tests. Ang optimal na strategy ay kombinasyon: snapshot tests ay sumasaklaw sa visual regression (render ng bawat screen sa base states), at UI tests ay sumasaklaw sa behavioral regression (click scenarios, input validation, navigation). Ang ganitong kombinasyon ay nagbibigay ng 90% kumpiyansa sa correctness ng interface na may minimal na CI execution time.
Sa Android, ang mga pangunahing tool ay Paparazzi at Shot. Ang Paparazzi mula sa Cash App ay nagre-render ng mga component sa test environment sa JVM nang walang emulator, gamit ang Layoutlib gravitational layout. Ang Shot mula sa Karumi ay kumukuha ng Instrumentation screenshots sa totoong device o emulator at inihahambing ang mga ito sa mga reference sa pamamagitan ng AShot library, na isinasaalang-alang ang mga pagkakaiba sa resolution at pixel density.
Paparazzi ay hindi nangangailangan ng pagpapatakbo ng emulator — ang render ay isinasagawa sa JVM sa pamamagitan ng Layoutlib, na nagbibigay ng bilis na maihahambing sa unit tests. Sinusuportahan ng library ang parehong View system at Jetpack Compose. Para sa Compose, ginagamit ang modifier na paparazzi.snapshot { MyComposable() }. Ang mga reference ay naka-imbak sa src/test/snapshots at awtomatikong inihahambing sa bawat pagtakbo. Ang maximum na porsyento ng pagkakaiba ay na-configure sa pamamagitan ng maxPercentDifference.
SnapshotTesting mula sa Point-Free ay sumusuporta sa paghahambing hindi lamang ng UIImage, kundi pati na rin ng mga string, JSON, Data at buong Core Data stores. Ginagawa nitong isang universal tool hindi lamang para sa UI snapshots, kundi para din sa pagsusuri ng serialization at decoding ng JSON responses. Para sa SwiftUI, ginagamit ang extension na assertSnapshot na may modifier na .image(on: .iPhone13). Ang recording strategy — record: true — ay lumilikha ng mga reference sa unang pagtakbo.
Para sa React Native, ang popular na solusyon ay react-native-testing-library sa kombinasyon ng jest-image-snapshot. Ang web approach sa snapshot testing ay dinadala sa mobile environment sa pamamagitan ng pag-render ng mga component sa Node.js environment na may kasunod na paghahambing ng JSON snapshots ng virtual DOM. Ang approach na ito ay mas mabilis kaysa native, ngunit hindi gaanong tumpak — hindi nito isinasaalang-alang ang platform-specific na feature ng pag-render ng font at system components. Para sa Flutter, ginagamit ang golden testing sa pamamagitan ng goldens toolkit.
Tingnan natin ang snapshot tests para sa Android (Paparazzi) at iOS (SnapshotTesting). Ang parehong halimbawa ay sumusuri sa hitsura ng isang component — user card na may avatar, pangalan at status. Ang test ay nagre-render ng component na may test data at inihahambing ang resulta sa reference na imahe na naka-imbak sa repository.
Ginagamit ng Paparazzi ang @Test annotation at snapshot() method para makuha ang render. Ang mga reference ay naka-imbak sa folder na src/test/snapshots at awtomatikong kinukuha sa susunod na pagtakbo para sa paghahambing.
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 ay gumagamit ng modifier na .snapshot() sa loob ng assertSnapshot. Awtomatikong tinutukoy ng library ang format — UIImage para sa UIView, String para sa text, Data para sa binary 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))
}
}
Ang tipikal na daloy ng trabaho ay may apat na yugto. Unang pagtakbo (record mode): lahat ng snapshot tests ay isinasagawa sa recording mode — ang mga reference na imahe ay nilikha at naka-imbak sa repository. Ang yugtong ito ay isinasagawa sa paunang pag-setup ng mga test o pagkatapos ng sinasadyang pagbabago ng interface. Pagkatapos ng recording, ang mga reference ay naka-commit kasama ng code — sila ay nagiging bahagi ng proyekto.
Sa mga susunod na pagtakbo, ang mga test ay gumagana sa comparison mode: bawat bagong render ay inihahambing sa reference. Kung may nakitang pagkakaiba, isang diff image ay nabubuo: ang mga pixel na tumutugma sa reference ay naka-highlight na berde, ang mga nagkakaiba ay naka-highlight na pula. Pinag-aaralan ng developer ang diff at gumagawa ng desisyon: kung ang pagbabago ay inaasahan (sinasadyang pagbabago ng disenyo), ang reference ay ina-update sa pamamagitan ng record command; kung hindi inaasahan — ang bug ay inaayos. Pag-update ng mga reference ay ginagawa sa pamamagitan ng isang beses na command: para sa Paparazzi ito ay `./gradlew recordPaparazzi`, para sa SnapshotTesting — `assertSnapshot(record: true)`.
Ayon sa Spotify Engineering Blog (2022), ang mga team na gumagamit ng inilarawang workflow ay gumugugol ng average na 2 minuto bawat test sa pagsusuri ng diff images. Sa isang set ng 50 snapshot tests, ang buong cycle ng pag-update ng reference ay tumatagal ng 15–20 minuto, na mas mabilis kaysa sa manu-manong pag-verify ng visual na pagbabago sa 50 screen.
Ang snapshot tests ay may pangunahing limitasyon. Sensitivity sa kapaligiran: ang parehong component ay maaaring mag-render nang iba sa iba’t ibang bersyon ng OS, density ng screen at configuration ng font. Ang mga reference na ginawa sa isang makina ay maaaring magkaiba mula sa render sa CI server. Ang solusyon — paggamit ng fixed environment parameters: isang specific na Layoutlib version para sa Paparazzi o eksaktong modelo ng device para sa SnapshotTesting.
Antipattern No. 1: giant snapshots — isang snapshot test na kumukuha ng buong screen ay nabigo sa bawat minimal na pagbabago ng anumang component. Ang tamang approach — pag-test ng mga indibidwal na component (button, card, input field) nang nakahiwalay. Bawat component ay sinusuri nang independyente, na nagbibigay ng tumpak na indikasyon ng source ng pagbabago. Antipattern No. 2: pagwawalang-bahala sa diff — awtomatikong pag-update ng mga reference nang walang pagsusuri ng diff images ay nagbabawas ng halaga ng snapshot tests sa zero. Bawat diff ay nangangailangan ng sinasadyang desisyon ng developer.
Ayon sa Better Engineering Blog (2023), ang snapshot tests ay nagbibigay ng pinakamalaking benepisyo sa pagsaklaw ng mga component ng design system at key screen sa base states — walang laman, may laman, error at boundary. Ang pagsaklaw ng animation at dynamic states sa pamamagitan ng snapshot tests ay hindi epektibo dahil sa non-determinism ng timestamp sa render — para sa mga ganitong scenario, ang video recording o manual QA checking ay mas angkop.
Mga Madalas Itanong
Hindi, ang snapshot tests ay sumusuri sa hitsura, samantalang ang UI tests ay sumusuri sa pag-uugali ng interface. Ang optimal na strategy ay pagsamahin ang parehong approach: snapshot para sa visual regression, UI tests para sa pagsusuri ng scenario at navigation. Ang snapshot ay sumasagot sa tanong na “mukha bang tama?”, ang UI tests ay “gumagana ba nang tama?”
Ang mga reference ay ina-update sa bawat sinasadyang pagbabago ng disenyo: bagong kulay ng tema, binagong distansya, pagdagdag o pag-alis ng mga elemento. Pag-update ay ginagawa sa pamamagitan ng record mode, pagkatapos ang diff images ay sinusuri sa code review upang matiyak na ang mga pagbabago ay naaayon sa inaasahan ng designer.
Una sa lahat, ang mga component ng design system — mga button, card, input field, modal windows. Pagkatapos ang mga key screen sa base states. Huwag i-test gamit ang snapshot ang animation, WebView, mapa at screen na may dynamic na content — para sa mga ito, ang snapshot ay nagbibigay ng false failures dahil sa non-determinism.
Gamitin ang parehong API Level para sa record at test modes. Para sa Paparazzi itakda ang specific na Layoutlib version sa configuration. Para sa SnapshotTesting ay i-fix ang modelo ng device. Ang mga reference na ginawa sa Android 14 ay maaaring magkaiba mula sa render sa Android 12 dahil sa mga pagbabago sa system font at Material theme.
Sa CI, ang snapshot tests ay tumatakbo sa verification mode (verify). Kung ang test ay nabigo, ang CI ay nagpapakita ng diff image sa build artifacts. Record mode (pag-update ng reference) ay isinasagawa nang lokal ng developer o sa isang hiwalay na CI task na may manual trigger. Ang mga reference na imahe ay dapat na naka-commit sa repository.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din