אנו משלבים בדיקות סנאפשט (Snapshot Testing) כדי לאמת אוטומטית שינויי ממשק משתמש באפליקציות iOS, Android ו-Flutter. כאשר מפתח משנה מרווח ברכיב אחד, בדיקת סנאפשט תופסת שינויי פריסה לא רצויים במסכים אחרים תוך שניות. ההטמעה המלאה שלנו כוללת הגדרת כלים, כתיבת בדיקות לרכיבים מרכזיים, ושילוב CI — ומפחיתה בדיקות רגרסיה ידניות פי 10.
למה בדיקות סנאפשט קריטיות לאפליקציות מובייל
ללא אימות UI אוטומטי, כל שינוי בסגנון או ברכיב יכול להכניס באגים ויזואליים שבדיקות יחידה לא תופסות. סקירה ידנית של מסכים לפני שחרור היא איטית ולא אמינה. בדיקות סנאפשט פותרות את זה: ריצה אחת מאמתת 100% מהמסכים. לקוחות בדרך כלל רואים הפחתה של 95% בבאגים ויזואליים וחוסכים $10,000–$50,000 בשנה בעלויות QA ידניות.
הרעיון פשוט: בריצה הראשונה, הבדיקה שומרת תמונת ייחוס או עץ רכיבים מסודר. בריצות הבאות, היא משווה לייחוס. אי-התאמה משמעותה בדיקה נכשלת.
השוואת כלים לבדיקות סנאפשט
| פלטפורמה | כלי | זמן בדיקה ממוצע | תמיכה ב-Compose/SwiftUI |
|---|---|---|---|
| iOS | swift-snapshot-testing | 1–3 שניות | SwiftUI (דרך UIView) |
| Android | Paparazzi | 200–500 אלפיות השנייה | Jetpack Compose |
| Flutter | Golden Tests | 0.5–1 שניות | Flutter Widget |
Paparazzi מהיר פי 20 מבדיקות צילום מסך עם אמולטור: 200 אלפיות השנייה לעומת 6 שניות לבדיקה. עבור ספרייה עם 200 רכיבים, זה 30 דקות לעומת 3 דקות.
iOS: iOSSnapshotTestCase
ב-iOS, בדיקות סנאפשט בנויות על pointfreeco/swift-snapshot-testing (לשעבר FBSnapshotTestCase). זהו הפתרון הבשל ביותר:
import SnapshotTesting
class ProfileViewControllerTests: XCTestCase {
func testProfileScreen() {
let vc = ProfileViewController(user: .mock)
assertSnapshot(of: vc, as: .image(on: .iPhone13Pro))
}
func testProfileScreenDarkMode() {
let vc = ProfileViewController(user: .mock)
assertSnapshot(of: vc, as: .image(on: .iPhone13Pro(.landscape), traits: .init(userInterfaceStyle: .dark)))
}
}import SnapshotTesting class ProfileViewControllerTests: XCTestCase { func testProfileScreen() { let vc = ProfileViewController(user: .mock) assertSnapshot(of: vc, as: .image(on: .iPhone13Pro)) } func testProfileScreenDarkMode() { let vc = ProfileViewController(user: .mock) assertSnapshot(of: vc, as: .image(on: .iPhone13Pro(.landscape), traits: .init(userInterfaceStyle: .dark))) } } בריצה הראשונה יוצר קובץ assertSnapshot. בריצות הבאות הוא משווה פיקסל אחר פיקסל. הסף הוא 0 — כל הבדל נחשב לכישלון.
אסטרטגיות סנאפשט נתמכות: __Snapshots__/ProfileViewControllerTests/testProfileScreen.1.png (צילום מסך), .image (עץ תצוגת טקסט), .recursiveDescription (מבנה). עבור ספריות רכיבים, .dump הוא התקן.
בעיית הפונטים ב-CI
עיבוד טקסט בסימולטור עשוי להיות שונה ממכונת CI עקב גרסאות פונטים שונות של המערכת. הפתרון הוא לנעול את הסימולטור (iPhone 15, iOS 17.4) ולהשתמש באותה גרסת Xcode. ב-.image דרך fastlane:
xcversion(version: "~> 15.3") Android: Paparazzi
עבור Android, הכלי הטוב ביותר הוא Paparazzi של Square. הוא אינו דורש אמולטור: הוא מעבד Views דרך xcversion בסביבת JVM, תוך שימוש ב-xcversion(version: "~> 15.3") (אותו מנוע כמו Android Studio Preview).
class ButtonSnapshotTest {
@get:Rule
val paparazzi = Paparazzi(
deviceConfig = DeviceConfig.PIXEL_6,
theme = "Theme.App"
)
@Test
fun primaryButton() {
paparazzi.snapshot {
PrimaryButton(
text = "Сохранить",
onClick = {}
)
}
}
}ריצה: LayoutInflater (הקלטת ייחוסים) ו-layoutlib (אימות).
Paparazzi תומך ב-Jetpack Compose עם class ButtonSnapshotTest { @get:Rule val paparazzi = Paparazzi( deviceConfig = DeviceConfig.PIXEL_6, theme = "Theme.App" ) @Test fun primaryButton() { paparazzi.snapshot { PrimaryButton( text = "Сохранить", onClick = {} ) } } } — אותו מנגנון.
Flutter: Golden Tests
ב-Flutter, בדיקות סנאפשט נקראות Golden Tests והן חלק מ-./gradlew recordPaparazziDebug:
testWidgets('CustomCard golden', (tester) async {
await tester.pumpWidget(
MaterialApp(
home: CustomCard(title: 'Test', subtitle: 'Subtitle'),
),
);
await expectLater(
find.byType(CustomCard),
matchesGoldenFile('goldens/custom_card.png'),
);
});
עדכון ייחוסים: ./gradlew verifyPaparazziDebug.
תלות פלטפורמה בקבצי golden היא בעיה ידועה. macOS מעבד פונטים אחרת מאשר Linux (CI). פתרון: אחסון קבצי golden שנוצרו ב-CI (Linux), ומקומית מפתחים מריצים paparazzi.snapshot { ComposableFunction() } רק על אותה מערכת הפעלה. לחלופין, השתמשו בחבילת flutter_test עם testWidgets('CustomCard golden', (tester) async { await tester.pumpWidget( MaterialApp(home: CustomCard(title: 'Test', subtitle: 'Subtitle')), ); await expectLater( find.byType(CustomCard), matchesGoldenFile('goldens/custom_card.png'), ); }); כדי לצמצם חלק מההבדלים.
שלבי ההטמעה
- ביקורת על ארכיטקטורת ה-UI הנוכחית – זיהוי רכיבים ומסכים שדורשים כיסוי.
- בחירת כלי מתאים – בחירה בין swift-snapshot-testing, Paparazzi או Golden Tests.
- הגדרת סביבת בדיקות – הגדרת תלויות פרויקט וסביבת CI.
- כתיבת 10–30 בדיקות סנאפשט – כיסוי מסכים מרכזיים ורכיבים לשימוש חוזר.
- שילוב אימות CI – הרצת שלב אימות בלבד; הקלטה מתבצעת מקומית.
- תיעוד תהליך העדכון – הדרכת צוות כיצד לתחזק ייחוסי סנאפשט.
איך בדיקות סנאפשט משתלבות ב-CI
אנו מגדירים את צינור ה-CI להריץ רק אימות (verify), בעוד הקלטת ייחוסים מתבצעת מקומית. זה מבטיח ששינויי UI לא יעברו ללא תשומת לב.
גורמים אופייניים לפערים ב-CI
- גרסאות פונטים שונות
- עיבוד שונה בסימולטור לעומת מכונת CI
- רזולוציית מסך וקנה מידה
- גרסאות Xcode ו-SDK
מומלץ לנעול את הסביבה ולהריץ הקלטת ייחוסים על אותה הגדרה כמו CI.
דוגמה מהפרקטיקה שלנו
לפרויקט אחד (לקוח שירותי פינטק), הטמענו בדיקות סנאפשט ב-Flutter. ספריית הרכיבים הכילה 120 ווידג'טים. לאחר הגדרת golden tests, זמן בדיקות הרגרסיה של ה-UI ירד משעתיים של סקירה ידנית ל-3 דקות של אימות אוטומטי. כל תמונות הייחוס מאוחסנות במאגר ומתעדכנות רק בכוונה תחילה.
מה כלול
- ניתוח ארכיטקטורת ה-UI הנוכחית ובחירת כלים
- הגדרת כלי בדיקות סנאפשט (iOS/Android/Flutter)
- כתיבת בדיקות למסכים ורכיבים מרכזיים (10–30 בדיקות)
- שילוב CI (GitHub Actions, GitLab CI או Bitrise)
- תיעוד על ניהול סנאפשטים ותהליך העדכון
- הדרכת צוות (1–2 שעות)
ניהול ייחוסי סנאפשט ב-Git
ייחוסי סנאפשט מאוחסנים במאגר. כמה כללים:
-
flutter test --update-goldens,flutter test --update-goldens,golden_toolkit— הוספה ל-loadAppFonts()כקובץ בינארי:__Snapshots__/ - בקשת משיכה עם שינויי UI חייבת לכלול סנאפשטים מעודכנים:
src/test/snapshots/ - ב-CI, הרצת אימות בלבד (
test/goldens/), לא הקלטה (.gitattributes). הקלטה מתבצעת רק מקומית או דרך workflow מיוחד
אם CI נכשל עקב אי-התאמה בסנאפשט, זו לא שגיאת בדיקה; זה אות לשינוי UI לא רצוי. זה דבר טוב.
לוח זמנים ועלות
הטמעה בסיסית (הגדרת כלים + 10–30 בדיקות) אורכת 2–3 ימים ועולה $3,000–$6,000. כיסוי מלא של ספריית רכיבים (50+ רכיבים) מוערך בנפרד ונע בין $8,000 ל-$15,000. לקוחות בדרך כלל מחזירים את ההשקעה תוך שלושה חודשים דרך הפחתת עלויות בדיקות ידניות, וחוסכים בממוצע $30,000 בשנה. יש לנו ניסיון של למעלה מ-5 שנים בפיתוח מובייל ו-30+ פרויקטים עם בדיקות אוטומטיות — אנו מבטיחים איכות ועמידה בלוחות זמנים.
קבלו ייעוץ לפרויקט שלכם — צרו קשר להערכה. נבחר את הכלי האופטימלי וניצור תוכנית הטמעה.







