Golden Test — ما هو، كيف تعمل اختبارات اللقطات والتطبيق

المؤلف: IT Sectr نُشر: 2026-04-10 وقت القراءة: 9 دق

Golden Test (اختبار اللقطة، الاختبار المرجعي) — طريقة لاختبار واجهة المستخدم البصري حيث تتم مقارنة العرض الحالي للمكون مع صورة مرجعية محفوظة مسبقاً (ملف golden). إذا تجاوزت تغييرات البكسل حداً معيناً، يفشل الاختبار ويُنتج صورة diff. يراجع المطور الـ diff وإما يقبل التغييرات (يُحدّث golden) أو يُصلح الخلل. اقرأ المزيد في مقالة Meta Engineering عن Paparazzi.

الرئيسية

  • Golden Test — مقارنة واجهة المستخدم الحالية مع صورة مرجعية لاكتشاف الانحدارات البصرية
  • صورة diff — عند فشل اختبار golden، يُنتج diff يُبرز البكسلات المتغيرة
  • Android — Paparazzi و Roborazzi لاختبار اللقطات لمكونات Compose و View
  • iOS — SwiftSnapshotTesting (pointfree.co) و iOSSnapshotTestCase من Uber لـ SwiftUI و UIKit
  • تكامل CI — تُجرى اختبارات golden على CI وتفشل عند تغييرات واجهة المستخدم غير المتوقعة

ما هو Golden Test وكيف يعمل؟

Golden Test — فحص آلي للمظهر البصري للمكون عبر مقارنة بكسل ببكسل مع المرجع. العملية: (1) يُنشئ المطور أو المختبر أول لقطة للمكون — هذا هو «golden» (المرجع). (2) يُحفظ ملف golden في المستودع بجانب الاختبار. (3) في التشغيلات اللاحقة، يُعيد الاختبار عرض المكون ويقارنه بـ golden المحفوظ. (4) إذا تطابقت الصور — الاختبار أخضر. إذا اختلفت — الاختبار أحمر مع diff. القرار: إما التغييرات متوقعة (تحديث golden) أو هذا خطأ.

كيف يُنشأ golden — تعرض المكتبة المكون في مخزن مؤقت خارج الشاشة (Android: Canvas، iOS: UIGraphicsImageRenderer) بدون شاشة حقيقية. هذا يعني أن اختبارات golden تعمل على CI بدون محاكي شاشة (virtual display)، مما يُسرّع التنفيذ. يستخدم Paparazzi على Android Layoutlib من Android Studio — نفس محرك Layout Editor. يستخدم iOSSnapshotTestCase عرض UIKit في CGImage. النتيجة — ملف PNG بحجم ثابت.

حجم ملفات golden وإدارة التخزين

ملفات golden — لقطة PNG لشاشة واحدة (1080x1920) تشغل 200–800 كيلوبايت حسب التعقيد. لمشروع به 500 اختبار golden، هذا ~100–400 ميغابايت في المستودع. الحلول: (1) تخزين golden في Git LFS. (2) استخدام ضغط PNG (pngcrush، oxipng). (3) تخزين golden في مخزن منفصل (S3) وتنزيلها أثناء البناء. في IT Sectr نخزن golden في Git LFS بحد أقصى 1 ميغابايت لكل ملف — هذا كافٍ لـ 90% من الاختبارات.

اختبارات golden غير المستقرة (Flaky) وحلها

اختبارات golden غير المستقرة — المشكلة الرئيسية لاختبارات golden. تُنتج وحدات معالجة رسومية مختلفة وإصدارات خطوط وanti-aliasing اختلافات دقيقة في البكسلات. الحلول: حد (نسبة مئوية مسموحة من البكسلات المختلفة)، مقارنة ضبابية (fuzzy comparison)، والتشغيل على وكلاء CI متطابقين (نفس GPU ونظام التشغيل وإصدار المحاكي). يستخدم Paparazzi مقارنة pixel-perfect، لذلك يجب أن تكون وكلاء CI متطابقين.

Golden Test مقابل Screenshot Test: ما الفرق؟

Golden Test — نوع من اختبارات اللقطات بمرجع ثابت. مصطلح «golden» يعني أن المرجع قد وافق عليه الفريق ويُخزن في المستودع. أي تغيير في الصورة يتطلب قراراً واعياً من المطور: تحديث golden أو إصلاح الكود. يعمل Golden Test على مستوى المكونات الفردية (Composable، UIView) ولا يتطلب جهازاً حقيقياً.

Screenshot Test — مفهوم أوسع. يمكن لاختبار اللقطة التقاط شاشة كاملة ببيانات حقيقية وتنقل وشريط حالة النظام ورسوم متحركة. غالباً ما تُجرى اختبارات اللقطات على أجهزة حقيقية أو محاكيات عبر UI Automator (Android) أو XCUITest (iOS). تعمل اختبارات golden في بيئة اختبار وحدة (JVM، XCTest) بدون محاكي وتلتقط فقط مكوناً واحداً.

الخاصيةGolden TestScreenshot Test
المستوىمكون/Composable/Viewشاشة كاملة
البيئةاختبار وحدة (مخزن خارج الشاشة)جهاز/محاكي
السرعة50–200 مللي ثانية لكل اختبار2–30 ثانية لكل اختبار
الرسوم المتحركةغير مدعومةمدعومة (مع توقفات)
CI بدون GPUيعمل (Layoutlib)يتطلب محاكي
صعوبة الإعدادمنخفضةعالية (محاكي/Device Farm)
عدم الاستقرارمتوسط (GPU مختلفة)عالي (محاكي، وقت)

استراتيجية التغطية: golden مقابل screenshot

Golden مقابل Screenshot — اختبارات golden للتحقق من مكونات UI الفردية (زر، بطاقة، حوار) عند كلCommit. اختبارات screenshot للتحقق الشامل (E2E) للشاشات الكاملة قبل الإصدار. توفر اختبارات golden تغذية راجعة سريعة للمطور، وتمنح اختبارات screenshot الثقة في سلامة التطبيق بأكمله. في IT Sectr نستخدم اختبارات golden لطلبات السحب (3–5 دقائق)، واختبارات screenshot ليلاً (30–60 دقيقة).

Paparazzi و Roborazzi: اختبار اللقطات على Android

Paparazzi — مكتبة من Cash App (Square) تعرض مكونات Android View و Jetpack Compose إلى PNG بدون محاكي. تستخدم Layoutlib (نفس محرك Android Studio Preview). الإعداد: إضافة إضافة Gradle، كتابة اختبار بـ @Test و @RunWith(PaparazziRule::class)، استدعاء paparazzi.snapshot(view). لا يدعم Paparazzi الرسوم المتحركة أو الفيديو أو الأجهزة الحقيقية — فقط عرض ثابت للمكونات.

kotlin
// build.gradle.kts (module)
plugins {
    id("app.cash.paparazzi") version "1.3.1"
}

// اختبار Golden لمكوّن Compose
class ButtonGoldenTest {

    @get:Rule
    val paparazzi = Paparazzi(
        Paparazzi.PaparazziSnapshotConfig(
            deviceConfig = DeviceConfig.PIXEL_6,
            theme = "android:Theme.Material.Light.NoActionBar"
        )
    )

    @Test
    fun primary_button() {
        paparazzi.snapshot {
            Button(
                onClick = { },
                modifier = Modifier.width(200.dp)
            ) {
                Text("Submit")
            }
        }
    }
}

Roborazzi — بديل لـ Paparazzi مع دعم Compose و View ومقارنة الصور. الفرق: يعمل Roborazzi عبر Robolectric ويدعم حداً (نسبة مئوية مسموحة لاختلاف البكسل). هذا يقلل عدم الاستقرار مع GPU المختلفة على CI. يمكن لـ Roborazzi أيضاً إنشاء رسوم متحركة GIF للتغييرات (قبل/بعد/diff)، وهو مناسب لمراجعة الكود. تنسيق ملف golden: PNG + بيانات JSON.

تحديث golden — بعد تغيير مقصود في UI، يحذف المطور ملفات golden القديمة ويُشغل الاختبارات مع علامة record. يُعيد Paparazzi إنشاء جميع ملفات golden. ثم يُدرج المطور ملفات golden الجديدة مع تغيير الكود. في مراجعة الكود، يرى المراجع diff لملفات golden القديمة والجديدة. إذا تمت الموافقة على التغييرات — يُدمج PR. إذا لا — يُصحح المطور الكود ويُعيد تشغيل الاختبارات. لا تُحدّث ملفات golden تلقائياً على CI — فقط محلياً.

SwiftSnapshotTesting و iOSSnapshotTestCase على iOS

SwiftSnapshotTesting — مكتبة من pointfree.co، مبتكرو Composable Architecture. تدعم UIView و UIViewController و CALayer و SwiftUI View. المبدأ: assertSnapshot(matching: view, as: .image). في التشغيل الأول، يُنشأ golden تلقائياً. في التشغيلات اللاحقة، يُقارن. إذا تجاوز الفرق الحد المسموح، يفشل الاختبار. يعمل SwiftSnapshotTesting عبر UIGraphicsImageRenderer، المتوافق مع CI (Xcode Cloud، GitHub Actions).

swift
import SnapshotTesting
import XCTest

final class ProfileCardSnapshotTests: XCTestCase {

    func test_profile_card_default() {
        let card = ProfileCard(
            name: "Alice",
            avatar: UIImage.testImage(),
            badge: "Pro"
        )
        let controller = UIHostingController(rootView: card)

        assertSnapshot(
            matching: controller,
            as: .image(on: .iPhoneSe),
            record: ProcessInfo.processInfo
                .environment["RECORD"] != nil
        )
    }
}

iOSSnapshotTestCase (سابقاً FBSnapshotTestCase) — مكتبة من Uber لـ UIKit. على عكس SwiftSnapshotTesting، يتطلب iOSSnapshotTestCase تحديد حجم الشاشة والاتجاه. ملفات golden هي PNG في مجلد ReferenceImages. الميزة: يعمل مع UIKit بدون SwiftUI ويدعم iOS 12+. العيب: لا يُحدّث golden تلقائياً — يجب تشغيله مع علامة record. SwiftSnapshotTesting أكثر حداثة ويُوصى به للمشاريع الجديدة.

Golden خاص بالجهاز — تختلف ملفات golden لأحجام واتجاهات الشاشة المختلفة. النهج القياسي: تسمية ملفات golden كـ TestName@3x~iPhone14.png. يُضيف SwiftSnapshotTesting تلقائياً لاحقة الجهاز إذا تم تحديد المعامل .image(on: .iPhoneSe). على Android، يستخدم Paparazzi DeviceConfig لتعيين الحجم. خزّن golden لكل عامل شكل جهاز مدعوم بشكل منفصل. لا تستخدم golden واحداً لأحجام مختلفة — هذا سيؤدي إلى اختبارات غير مستقرة.

العمل مع ملفات golden في CI وإدارة التحديثات

خط أنابيب CI — يجب تشغيل اختبارات golden في كل طلب سحب. إذا فشل اختبار، يُظهر CI صورة diff كقطعة بناء. يراجع المطور الـ diff ويتخذ قراراً. مهم: ملفات golden المُنشأة على CI لا تُدرج أبداً تلقائياً. فقط توليد محلي من قبل المطور بعد تغيير مقصود. تدعم GitHub Actions و GitLab CI رفع القطع (png، html) لعرض الـ diff في المتصفح.

حجم المستودع — تنمو ملفات golden بسرعة. 500 اختبار = 100–400 ميغابايت من PNG. الحلول: (1) Git LFS — يُخزن كل golden في LFS، يُستنسخ فقط عند checkout. (2) تخزين golden في مستودع منفصل وإدراجه كوحدة فرعية. (3) S3 + تخزين مؤقت — golden على S3، CI يُنزل فقط الملفات المتغيرة حسب المجموع الاختباري. في IT Sectr نستخدم Git LFS مع track *.png filter=lfs diff=lfs merge=lfs text=false. محلياً، توجد ملفات golden في src/test/goldens/.

مراجعة كود golden — لا يُظهر git diff العادي تغييرات PNG. الحلول: (1) GitHub يفتح صور PNG عند النقر. (2) استخدام Review Apps حيث يكون diff golden مرئياً في المتصفح. (3) إنشاء تقرير HTML بأعمدة قبل/بعد/diff. يُنشئ Paparazzi تقرير HTML بثلاثة أعمدة: فعلي، متوقع، diff. يُرفق التقرير بقطع CI. يراجع المراجعون التقرير دون تنزيل الملفات محلياً.

متى تُحدّث golden — فقط بعد تغيير واعٍ في UI. تغيير الخط، اللون، الحشوة، الأيقونة — يجب تحديث golden. إضافة زر جديد، إعادة ترتيب العناصر — يجب تحديث golden. إصلاح خطأ يُغير المظهر البصري — يجب تحديث golden. إعادة هيكلة بدون تغييرات UI — يجب ألا يتغير golden. إذا تغير golden بدون تغييرات في كود UI — هذا اختبار غير مستقر بسبب البيئة، ابحث عن السبب في وكلاء CI أو إصدارات التبعيات.

الأسئلة الشائعة

ما الفرق بين Golden Test و Screenshot Test؟

Golden Test — اختبار لقطة على مستوى المكون في بيئة اختبار وحدة (سريع، بدون محاكي). Screenshot Test — يلتقط الشاشة الكاملة على جهاز أو محاكي (أبطأ لكن واقعي). يعمل golden مع مخزن خارج الشاشة، screenshot مع شاشة حقيقية. Golden مناسب لـ CI عند كل commit، screenshot للتشغيل الليلي قبل الإصدار.

كيف نتعامل مع اختبارات golden غير المستقرة؟

الأسباب الرئيسية: (1) GPU مختلفة على CI — استخدم وكلاء CI متطابقين. (2) إصدارات خطوط مختلفة — ثبّت إصدار نظام التشغيل. (3) anti-aliasing مختلف — اضبط حداً (Roborazzi، iOSSnapshotTestCase). (4) الرسوم المتحركة — عطّل الرسوم المتحركة في الاختبارات. (5) عناصر النظام (شريط الحالة) — استخدم تهيئة جهاز بدون حواف. Paparazzi ليس عرضة لعدم الاستقرار بفضل Layoutlib.

هل يمكن استخدام Golden Test مع Jetpack Compose؟

نعم. Paparazzi لديه دعم مدمج لـ Compose عبر paparazzi.snapshot { }. يدعم Roborazzi أيضاً Compose. على iOS، يعمل SwiftSnapshotTesting مع SwiftUI عبر UIHostingController. تُعرض مكونات Compose عبر Layoutlib، SwiftUI عبر عرض UIKit. القيد: الرسوم المتحركة لـ Compose و SwiftUI غير مدعومة — يلتقط اختبار golden فقط الحالة الأولية.

كيف نقبل تغييرات golden تلقائياً؟

لا تقم أبداً بأتمتة قبول golden على CI. فقط محلياً: يحذف المطور ملفات golden القديمة من الدليل ويُشغل الاختبارات مع علامة record (Paparazzi: record=true، SwiftSnapshotTesting: record=true). تُعاد إنشاء ملفات golden. يراجع المطور كل golden للتأكد من صحته، ويُدرج التغييرات مع الكود. القبول التلقائي على CI سيؤدي إلى أخطاء UI غير مكتشفة.

هل تُبطئ اختبارات Golden البناء؟

اختبارات golden أسرع من الاختبارات الآلية (UI Automator، XCUITest). اختبار golden واحد يُنفذ في 50–200 مللي ثانية (Paparazzi: 100–150 مللي ثانية على MacBook Pro متوسط). 500 اختبار golden = 25–100 ثانية. قارن مع اختبارات screenshot عبر المحاكي: 5–30 ثانية لكل اختبار. لا تُبطئ اختبارات golden البناء: 100 اختبار = ~15 ثانية، وهو مقبول للفحص قبل الدمج.

الملخص

  • Golden Test — اختبار بصري لمكونات UI عبر المقارنة مع صورة PNG مرجعية
  • العملية — عرض المكون في مخزن خارج الشاشة، مقارنة بكسل ببكسل، diff عند عدم التطابق
  • Android — Paparazzi (Compose/View، Layoutlib) و Roborazzi (Compose/View، حد، Robolectric)
  • iOS — SwiftSnapshotTesting (pointfree) و iOSSnapshotTestCase من Uber لـ UIKit و SwiftUI
  • خط أنابيب CI — اختبارات golden في كل PR، قطع diff، تحديث golden محلي فقط
  • Git LFS — إلزامي لتخزين ملفات PNG (100–400 ميغابايت لـ 500 اختبار)
  • عدم الاستقرار — مرتبط بـ GPU والخطوط وanti-aliasing؛ يُحل بالحد ووكلاء CI متطابقين

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا