سنیپ شاٹ ٹیسٹنگ صارف انٹرفیس کی خودکار تصدیق کا ایک طریقہ ہے جس میں موجودہ اسکرین کی حالت کا موازنہ پچھلے ٹیسٹ رن میں محفوظ کردہ ریفرنس امیج (سنیپ شاٹ) سے کیا جاتا ہے۔ کسی بھی بصری تفاوت کو ایک تبدیلی کے طور پر ریکارڈ کیا جاتا ہے جس کے لیے ڈویلپر کی تصدیق درکار ہوتی ہے۔ UI ٹیسٹوں کے برعکس جو عناصر کی موجودگی کی جانچ کرتے ہیں، سنیپ شاٹ ٹیسٹ پکسل سطح کی تبدیلیوں — نقل مکانی، رنگ کے انحراف اور لے آؤٹ کے مسائل — کا پتہ لگاتے ہیں۔ Android Developers, 2024 کے مطابق، سنیپ شاٹ ٹیسٹنگ روایتی UI ٹیسٹوں سے چھوٹ جانے والے 30% تک بصری ریگریشنز کا پتہ لگاتی ہے، جو اسے ایک مستقل انٹرفیس کو برقرار رکھنے کے لیے ایک ناگزیر ٹول بناتی ہے۔
اہم نکات
سنیپ شاٹ ٹیسٹنگ ایک تکنیک ہے جس میں ایک ٹیسٹ UI جزو کو رینڈر کرتا ہے، نتیجے میں ملنے والی تصویر کو ریفرنس کے طور پر محفوظ کرتا ہے، اور بعد کے رنز میں موجودہ رینڈر کا اس ریفرنس سے موازنہ کرتا ہے۔ اگر تصاویر مماثل ہوں — ٹیسٹ پاس ہو جاتا ہے۔ اگر فرق پایا جاتا ہے — ٹیسٹ ناکام ہو جاتا ہے، اور ڈویلپر کو تبدیل شدہ پکسلز کو نمایاں کرنے والی ایک diff تصویر موصول ہوتی ہے۔ یہ تکنیک ویب ڈویلپمنٹ (Jest سنیپ شاٹس) سے مستعار لی گئی ہے اور موبائل پلیٹ فارمز کے لیے ڈھال لی گئی ہے۔
سنیپ شاٹ ٹیسٹوں کی بنیادی قدر غیر متوقع بصری تبدیلیوں کا خودکار پتہ لگانا ہے۔ ایک ڈویلپر عالمی تھیم میں رنگ سکیم تبدیل کر سکتا ہے اور غلطی سے درجنوں اسکرینوں کو متاثر کر سکتا ہے۔ UI ٹیسٹ جو بٹن اور متن کی موجودگی کی جانچ کرتے ہیں، اسے محسوس نہیں کریں گے۔ ایک سنیپ شاٹ ٹیسٹ متاثرہ ہر اسکرین پر ہر پکسل تبدیلی کو کیپچر کرے گا، تبدیلی کے اثرات کی مکمل تصویر فراہم کرے گا۔
Mobile DevOps Summit 2023 سروے کے مطابق، کلاسک UI ٹیسٹوں کے علاوہ سنیپ شاٹ ٹیسٹنگ استعمال کرنے والی ٹیمیں ریلیز میں بصری نقائص کی تعداد میں 40% تک کمی لاتی ہیں۔ یہ نقطہ نظر خاص طور پر ڈیزائن سسٹمز اور اجزاء پر مبنی فن تعمیر والے منصوبوں میں مؤثر ہے، جہاں ایک بنیادی جزو کی تبدیلی ایپلیکیشن کے درجنوں اسکرینوں کو متاثر کر سکتی ہے۔
بنیادی فرق تصدیق کے مقصد میں ہے۔ UI ٹیسٹ انٹرفیس عناصر کی موجودگی، حالت اور رویے کی جانچ کرتے ہیں: “بٹن نظر آ رہا ہے”، “متن میں خرابی کا پیغام ہے”، “دبانے پر نئی اسکرین کھلتی ہے”۔ سنیپ شاٹ ٹیسٹ مکمل بصری ظاہری شکل کی جانچ کرتے ہیں: عناصر کی پوزیشننگ، مارجن، رنگ، فونٹ، سائے اور گول کونے۔ ایک سنیپ شاٹ ٹیسٹ اس سوال کا جواب دیتا ہے “کیا اسکرین توقع کے مطابق نظر آتی ہے؟”، جبکہ UI ٹیسٹ جواب دیتا ہے “کیا اسکرین توقع کے مطابق کام کرتی ہے؟”
عملدرآمد کی رفتار بھی مختلف ہوتی ہے۔ UI ٹیسٹ ایمولیٹر یا حقیقی ڈیوائس پر چلتے ہیں، مکمل ایپلیکیشن لوڈنگ کی ضرورت ہوتی ہے، اور فی منظر نامہ 10 سیکنڈ سے ایک منٹ تک لیتے ہیں۔ Paparazzi جیسی لائبریریاں استعمال کرنے والے سنیپ شاٹ ٹیسٹ ایمولیٹر چلائے بغیر ورچوئل ماحول میں اجزاء کو رینڈر کرتے ہیں، جس سے ٹیسٹ کا وقت 100–500 ملی سیکنڈ تک کم ہو جاتا ہے۔ سنیپ شاٹ ٹیسٹوں کا ایک مکمل سیٹ (50–100 اسکرینیں) UI ٹیسٹوں کے موازنہ سیٹ کے لیے 30–60 منٹ کے بجائے 2–5 منٹ میں عملدرآمد ہوتا ہے۔
تاہم، سنیپ شاٹ ٹیسٹ UI ٹیسٹوں کی جگہ نہیں لیتے۔ بہترین حکمت عملی ایک مجموعہ ہے: سنیپ شاٹ ٹیسٹ بصری ریگریشن کا احاطہ کرتے ہیں (بنیادی حالتوں میں ہر اسکرین کا رینڈر)، جبکہ UI ٹیسٹ رویوں کے پہلوؤں (کلک منظر نامے، ان پٹ کی توثیق، نیویگیشن) کا احاطہ کرتے ہیں۔ یہ مجموعہ کم سے کم CI رن ٹائم کے ساتھ انٹرفیس کی درستگی میں 90% اعتماد فراہم کرتا ہے۔
اینڈرائیڈ پر، اہم اوزار Paparazzi اور Shot ہیں۔ Cash App کا Paparazzi Layoutlib گریویٹی لے آؤٹ استعمال کرتے ہوئے ایمولیٹر کے بغیر JVM ٹیسٹ ماحول میں اجزاء کو رینڈر کرتا ہے۔ Karumi کا Shot حقیقی ڈیوائس یا ایمولیٹر پر Instrumentation اسکرین شاٹس لیتا ہے اور AShot لائبریری کے ذریعے ان کا ریفرنسز سے موازنہ کرتا ہے، ریزولوشن اور پکسل کثافت میں فرق کو مدنظر رکھتے ہوئے۔
Paparazzi کو ایمولیٹر چلانے کی ضرورت نہیں — رینڈرنگ Layoutlib کے ذریعے JVM پر کی جاتی ہے، جو یونٹ ٹیسٹوں کے برابر رفتار فراہم کرتی ہے۔ لائبریری View سسٹم اور Jetpack Compose دونوں کو سپورٹ کرتی ہے۔ Compose کے لیے، paparazzi.snapshot { MyComposable() } موڈیفائر استعمال کریں۔ ریفرنسز src/test/snapshots میں محفوظ ہوتے ہیں اور ہر رن پر خود بخود موازنہ کیے جاتے ہیں۔ زیادہ سے زیادہ فرق فیصد maxPercentDifference کے ذریعے ترتیب دیا جاتا ہے۔
Point-Free کا SnapshotTesting نہ صرف UIImage بلکہ سٹرنگز، JSON، Data اور مکمل Core Data سٹورز کے موازنہ کی بھی حمایت کرتا ہے۔ یہ اسے نہ صرف UI سنیپ شاٹس کے لیے بلکہ JSON جوابات کی سیریلائزیشن اور ڈی کوڈنگ کی تصدیق کے لیے بھی ایک ورسٹائل ٹول بناتا ہے۔ SwiftUI کے لیے، .image(on: .iPhone13) موڈیفائر کے ساتھ assertSnapshot ایکسٹینشن استعمال کریں۔ record: true حکمت عملی پہلے رن پر ریفرنسز بناتی ہے۔
React Native کے لیے، مقبول حل jest-image-snapshot کے ساتھ react-native-testing-library کا مجموعہ ہے۔ سنیپ شاٹ ٹیسٹنگ کا ویب طریقہ کار Node.js ماحول میں اجزاء کو رینڈر کرکے اور بعد میں ورچوئل DOM کے JSON سنیپ شاٹس کا موازنہ کرکے موبائل ماحول میں منتقل کیا جاتا ہے۔ یہ طریقہ کار native سے تیز ہے لیکن کم درست — یہ پلیٹ فارم کے مخصوص فونٹ رینڈرنگ اور سسٹم اجزاء کی خصوصیات کو مدنظر نہیں رکھتا۔ Flutter کے لیے، goldens ٹول کٹ کے ذریعے گولڈن ٹیسٹنگ استعمال کی جاتی ہے۔
آئیے Android (Paparazzi) اور iOS (SnapshotTesting) کے لیے سنیپ شاٹ ٹیسٹ دیکھتے ہیں۔ دونوں مثالیں ایک جزو کی ظاہری شکل کی تصدیق کرتی ہیں — اوتار، نام اور حیثیت کے ساتھ ایک صارف کارڈ۔ ٹیسٹ جزو کو رینڈر کرتا ہے ٹیسٹ ڈیٹا کے ساتھ اور نتیجے کا موازنہ ریپوزٹری میں محفوظ کردہ ریفرنس امیج سے کرتا ہے۔
Paparazzi رینڈر کو کیپچر کرنے کے لیے @Test انوٹیشن اور snapshot() طریقہ استعمال کرتا ہے۔ ریفرنسز src/test/snapshots فولڈر میں محفوظ ہوتے ہیں اور موازنہ کے لیے اگلے رن پر خود بخود لوڈ ہوتے ہیں۔
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 کے اندر .snapshot() موڈیفائر استعمال کرتا ہے۔ لائبریری خود بخود فارمیٹ کا تعین کرتی ہے — UIView کے لیے UIImage، متن کے لیے String، بائنری ڈیٹا کے لیے 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))
}
}
عام ورک فلو چار مراحل پر مشتمل ہے۔ پہلا رن (ریکارڈ موڈ): تمام سنیپ شاٹ ٹیسٹ ریکارڈ موڈ میں عملدرآمد ہوتے ہیں — ریفرنس امیجز بنائی جاتی ہیں اور ریپوزٹری میں محفوظ کی جاتی ہیں۔ یہ مرحلہ ابتدائی ٹیسٹ سیٹ اپ کے دوران یا انٹرفیس میں جان بوجھ کر تبدیلی کے بعد انجام دیا جاتا ہے۔ ریکارڈنگ کے بعد، ریفرنسز کوڈ کے ساتھ کمٹ کیے جاتے ہیں — وہ پروجیکٹ کا حصہ بن جاتے ہیں۔
بعد کے رنز پر، ٹیسٹ موازنہ موڈ میں کام کرتے ہیں: ہر نئے رینڈر کا ریفرنس سے موازنہ کیا جاتا ہے۔ اگر فرق پایا جاتا ہے، تو diff تصویر بنائی جاتی ہے: ریفرنس سے مماثل پکسلز سبز رنگ میں نمایاں ہوتے ہیں، مختلف والے سرخ میں۔ ڈویلپر diff کا مطالعہ کرتا ہے اور فیصلہ کرتا ہے: اگر تبدیلی متوقع ہے (جان بوجھ کر ڈیزائن تبدیلی)، تو ریفرنس ریکارڈ کمانڈ سے اپ ڈیٹ کیا جاتا ہے؛ اگر غیر متوقع ہے — بگ ٹھیک کیا جاتا ہے۔ ریفرنس اپ ڈیٹ ایک بار کے کمانڈ سے کیا جاتا ہے: Paparazzi کے لیے یہ `./gradlew recordPaparazzi` ہے، SnapshotTesting کے لیے — `assertSnapshot(record: true)`۔
Spotify Engineering Blog (2022) کے مطابق، بیان کردہ ورک فلو استعمال کرنے والی ٹیمیں diff تصاویر کے تجزیے پر فی ٹیسٹ اوسطاً 2 منٹ خرچ کرتی ہیں۔ 50 سنیپ شاٹ ٹیسٹوں کے سیٹ کے ساتھ، ایک مکمل ریفرنس اپ ڈیٹ سائیکل میں 15–20 منٹ لگتے ہیں، جو 50 اسکرینوں پر بصری تبدیلیوں کی دستی تصدیق سے نمایاں طور پر تیز ہے۔
سنیپ شاٹ ٹیسٹوں کی بنیادی حدود ہیں۔ ماحول کی حساسیت: ایک ہی جزو مختلف OS ورژنز، اسکرین کثافتوں اور فونٹ کنفیگریشنز پر مختلف طریقے سے رینڈر ہو سکتا ہے۔ ایک مشین پر بنائے گئے ریفرنسز CI سرور پر رینڈر سے مختلف ہو سکتے ہیں۔ حل مقررہ ماحول کے پیرامیٹرز استعمال کرنا ہے: Paparazzi کے لیے مخصوص Layoutlib ورژن یا SnapshotTesting کے لیے عین ڈیوائس ماڈل۔
مخالف پیٹرن #1: بہت بڑے سنیپ شاٹس — ایک سنیپ شاٹ ٹیسٹ جو پوری اسکرین کو کیپچر کرتا ہے، کسی بھی جزو میں معمولی تبدیلی پر ناکام ہو جاتا ہے۔ صحیح طریقہ کار انفرادی اجزاء (بٹن، کارڈ، ان پٹ فیلڈ) کو الگ تھلگ کرکے ٹیسٹ کرنا ہے۔ ہر جزو آزادانہ طور پر ٹیسٹ کیا جاتا ہے، جو تبدیلی کے ماخذ کی صحیح نشاندہی فراہم کرتا ہے۔ مخالف پیٹرن #2: diff کو نظر انداز کرنا — diff تصاویر کا تجزیہ کیے بغیر خود بخود ریفرنسز کو اپ ڈیٹ کرنا سنیپ شاٹ ٹیسٹوں کی قدر کو صفر کر دیتا ہے۔ ہر diff کے لیے ڈویلپر کے باشعور فیصلے کی ضرورت ہوتی ہے۔
Better Engineering Blog (2023) کے مطابق، سنیپ شاٹ ٹیسٹ سب سے زیادہ فائدہ اس وقت دیتے ہیں جب وہ ڈیزائن سسٹم کے اجزاء اور بنیادی حالتوں — خالی، بھرا ہوا، خرابی اور حد — میں کلیدی اسکرینوں کا احاطہ کرتے ہیں۔ رینڈرنگ میں ٹائم سٹیمپ کی غیر متعین نوعیت کی وجہ سے سنیپ شاٹ ٹیسٹوں کے ذریعے اینیمیشنز اور متحرک حالتوں کا احاطہ کرنا غیر موثر ہے — ایسے منظرناموں کے لیے ویڈیو ریکارڈنگ یا دستی QA جانچ زیادہ موزوں ہے۔
اکثر پوچھے جانے والے سوالات
نہیں، سنیپ شاٹ ٹیسٹ بصری ظاہری شکل کی جانچ کرتے ہیں، جبکہ UI ٹیسٹ انٹرفیس کے رویے کی جانچ کرتے ہیں۔ بہترین حکمت عملی دونوں طریقوں کو یکجا کرنا ہے: بصری ریگریشن کے لیے سنیپ شاٹس، منظرناموں اور نیویگیشن کے لیے UI ٹیسٹ۔ سنیپ شاٹس جواب دیتے ہیں “کیا یہ صحیح نظر آتا ہے”، UI ٹیسٹ جواب دیتے ہیں “کیا یہ صحیح کام کرتا ہے”۔
ریفریش ہر باشعور ڈیزائن تبدیلی پر اپ ڈیٹ کیے جاتے ہیں: نیا تھیم رنگ، تبدیل شدہ مارجن، عناصر کا اضافہ یا ہٹانا۔ اپ ڈیٹ ریکارڈ موڈ کے ذریعے کیا جاتا ہے، جس کے بعد کوڈ ریویو میں diff تصاویر کا جائزہ لیا جاتا ہے تاکہ یہ یقینی بنایا جا سکے کہ تبدیلیاں ڈیزائنر کی توقعات سے مطابقت رکھتی ہیں۔
سب سے پہلے، ڈیزائن سسٹم کے اجزاء — بٹن، کارڈز، ان پٹ فیلڈز، موڈل ونڈوز۔ پھر بنیادی حالتوں میں کلیدی اسکرینیں۔ سنیپ شاٹس سے ٹیسٹ نہ کریں اینیمیشنز، WebView، نقشے اور متحرک مواد والی اسکرینیں — غیر متعینیت کی وجہ سے سنیپ شاٹس جھوٹی ناکامیاں دیتے ہیں۔
ریکارڈ اور ٹیسٹ موڈ دونوں کے لیے ایک ہی API Level استعمال کریں۔ Paparazzi کے لیے، کنفیگریشن میں مخصوص Layoutlib ورژن بتائیں۔ SnapshotTesting کے لیے، ڈیوائس ماڈل مقرر کریں۔ Android 14 پر بنائے گئے ریفرنسز سسٹم فونٹس اور Material تھیم میں تبدیلیوں کی وجہ سے Android 12 پر رینڈر سے مختلف ہو سکتے ہیں۔
CI میں، سنیپ شاٹ ٹیسٹ تصدیقی موڈ (verify) میں چلتے ہیں۔ اگر کوئی ٹیسٹ ناکام ہوتا ہے، CI بلڈ آرٹیفیکٹ میں diff تصویر دکھاتا ہے۔ ریکارڈ موڈ (ریفریش اپ ڈیٹ) ڈویلپر کے ذریعے مقامی طور پر یا دستی ٹرگر کے ساتھ علیحدہ CI ٹاسک میں انجام دیا جاتا ہے۔ ریفرنس امیجز کو ریپوزٹری میں کمٹ کیا جانا چاہیے۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں