الاختبارات البصرية غير المستقرة (Flaky): لماذا تدمر الـ QA وكيف تُثبّتها

الاختبارات البصرية غير المستقرة (Flaky): لماذا تدمر الـ QA وكيف تُثبّتها

الاختبار غير المستقر (أو الاختبار المتقلّب) هو اختبار يُنتج نتائج مختلفة — نجاحًا أو فشلًا — لنفس الشفرة البرمجية ونفس التهيئة، دون أيّ تعديل على النظام قيد الاختبار.

إليك رأيًا قد يثير استياءك: الاختبار البصري غير المستقر أسوأ من انعدام الاختبار تمامًا. وليس هذا استفزازًا فارغًا. الاختبار الغائب لا يُكلّف شيئًا على المدى اليومي. لا يُعطّل خطّ الأنابيب (pipeline). لا يستهلك وقت فريقك. لا يُدمّر الثقة في البنية التحتية للاختبارات لديك. أمّا الاختبار غير المستقر فيفعل كلّ ذلك، يومًا بعد يوم، بشكل مُتسلّل — لأنّ كلّ إخفاق كاذب يبدو مُقنعًا بما يكفي ليستوجب التحقيق.

إنّ البيانات التي نشرتها Google حول أنظمة الاختبارات الخاصة بها صادقة: حوالي 1.5 بالمائة من اختباراتها غير مستقرة في أيّ وقت مُعطًى، غير أنّ هذه الاختبارات تستهلك حصة غير متناسبة من وقت المهندسين. إذا كانت شركة بحجم Google وبما تملكه من كفاءة تقنية لم تتمكّن من القضاء على هذه المشكلة، فهذا ليس سؤالًا تافهًا. وفي المجال المحدّد للاختبار البصري، تتفاقم المشكلة بسبب طبيعة ما يتمّ مقارنته ذاته.

لماذا تكون الاختبارات البصرية عُرضةً بشكل خاص لعدم الاستقرار

يُدخل الاختبار البصري المؤتمت طبقة من عدم الحتمية لا تعرفها الاختبارات الوحدوية أو الوظيفية. فالاختبار الوحدوي يتحقّق من أنّ دالّة تُعيد القيمة الصحيحة. والاختبار الوظيفي يتحقّق من أنّ زرًا يُطلق الإجراء الصحيح. هذه النتائج ثنائية وحتمية.

أمّا الاختبار البصري فيتحقّق من أنّ العرض المرئي لواجهتك يُطابق صورة مرجعية. وعرض صفحة ويب هو نتاج سلسلة معقّدة من العمليات، كلّ منها يُدخل تباينًا خاصًا به: تحليل HTML، وتطبيق CSS، وتنفيذ JavaScript، وتحميل الموارد الخارجية، وحساب التخطيط، والتنقيط (rasterization)، والتركيب (composition).

الأسباب الأربعة الرئيسية لعدم استقرار الاختبارات البصرية

التوقيت: المشكلة التي لا يمكنك تجاهلها

الويب بطبيعته غير متزامن. عندما تطلب من المتصفح التقاط لقطة شاشة، هل الصفحة جاهزة فعلًا؟ الجواب يكون في معظم الأحيان: يعتمد الأمر.

تحميل الصفحة ليس حدثًا واحدًا — بل هو سلسلة متتالية من الأحداث. فـ HTML يُحلَّل، وCSS يُطبَّق، والبرامج النصية تُنفَّذ، والصور تُحمَّل، وخطوط الويب تُطبَّق، وطلبات الـ API تُرجع البيانات. لكلّ خطوة مدّة متغيّرة. والاستراتيجية الكلاسيكية المتمثّلة في الانتظار حتى "الجاهزية" — سواء عبر الحدث DOMContentLoaded أو حدث load أو حالة network idle — لا تضمن اكتمال العرض المرئي.

النتيجة: لقطتك تلتقط أحيانًا صفحة كاملة، وأحيانًا صفحة في منتصف عملية العرض.

الرسوم المتحركة: حركة في وسط ثابت

لقطة الشاشة صورة ثابتة. والرسوم المتحركة تغيير مستمر. الاثنان غير متوافقين جوهريًا في سياق المقارنة المؤتمتة. فإذا كانت صفحتك تحتوي على رسوم متحركة بمدّة 300 مللي ثانية تُطلَق عند التحميل، فإنّ لحظة الالتقاط بالضبط بالنسبة إلى بداية الرسوم المتحركة تتفاوت بين عمليات التشغيل.

والرسوم المتحركة اللانهائية (مؤشّرات التحميل، وهيكل التحميل skeleton loaders) أسوأ: لا توجد لحظة "مستقرة" يمكن التقاط لقطة الشاشة فيها.

المحتوى الديناميكي: كلّ ما يتغيّر من دون تدخّلك

التواريخ والأوقات، والإعلانات، والصور الرمزية المُولَّدة عشوائيًا، والإشعارات في الوقت الفعلي، وعدّادات الزوار — كلّها تتغيّر بين عمليات تشغيل الاختبار. وكلّ تباين يُكتَشف كاختلاف بصري. وكلّ اختلاف يُؤدّي إلى فشل الاختبار.

الشبكة والبنية التحتية: متغيّرات لا تتحكّم بها

يعمل اختبارك في بيئة تعتمد على موارد خارجية: خوادم الـ API، وشبكات توزيع المحتوى (CDN) للصور والخطوط، وخدمات الطرف الثالث. وكمون الشبكة يتغيّر بين عمليات التشغيل. وفي خطّ أنابيب CI/CD، تتفاقم المشكلة — إذ يُشارك عامل CI الموارد مع مهام أخرى.

التكلفة الحقيقية للاختبارات غير المستقرة

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

لكنّ التكلفة الأكثر تدميرًا هي التكلفة غير المرئية: فقدان الثقة. فعندما يتعلّم فريقك أنّ الاختبارات البصرية "تفشل طوال الوقت" من دون سبب، يطوّر لديه ردّ فعل تلقائي يتمثّل في إعادة التشغيل. وفي اليوم الذي يفشل فيه اختبار بسبب خلل حقيقي، يكون ردّ الفعل هو نفسه: إعادة التشغيل. فيصل الخلل إلى بيئة الإنتاج.

لهذه الظاهرة اسم: "تأثير الصيّاح بالذئب". ومتى رسخت، أصبح من الصعب جدًا عكسها.

استراتيجيات التثبيت الفعّالة

التحكّم في بيئة العرض

استخدم متصفحًا بدون واجهة (headless) داخل حاوية مُتحكَّم بها بدقّة شاشة ثابتة، وخطوط مُثبَّتة مسبقًا، وتهيئة شبكة حتمية. ثبِّت إصدار المتصفح، وعطّل العرض عبر وحدة معالجة الرسومات (GPU)، واضبط حجم منفذ العرض (viewport) على قيمة ثابتة.

تحييد الرسوم المتحركة

أدخِل ورقة أنماط تُجبر جميع الرسوم المتحركة والانتقالات على مدّة صفرية. وهذا يُجمّد فورًا جميع العناصر المتحرّكة في حالتها النهائية.

تثبيت المحتوى الديناميكي

ثبِّت التواريخ والأوقات، وعطّل أدوات الطرف الثالث، واستبدل بيانات الـ API ببيانات مزيّفة، واستبدل الصور الرمزية المُولَّدة بصور ثابتة في بيانات الاختبار. الهدف هو بيئة يكون فيها المتغيّر الوحيد هو شفرة واجهتك.

الانتظار الذكي

بدلًا من التأخيرات الثابتة (انتظر ثلاث ثوانٍ)، استخدم استراتيجيات انتظار مبنية على الحالة. انتظر حتى تصبح العناصر الحرجة مرئية، والصور محمّلة، والخطوط مُطبَّقة، وطلبات الشبكة مكتملة.

تبنّي مقارنة تتحمّل الضوضاء

المقارنة بكسل بكسل هي الأكثر حساسية لعدم حتمية العرض. والخوارزميات الإدراكية (مثل SSIM وpHash) أكثر تسامحًا. أمّا النهج الهيكلي — المتمثّل في مقارنة DOM وخصائص CSS المحسوبة بدلًا من البكسلات — فهو الأكثر مقاومة لضوضاء العرض، لأنّه يتجاهل بطبيعته التباينات تحت البكسل التي تسبّب معظم حالات الفشل المتقطّع.

الاختبار البصري بدون شفرة كحلّ لمشكلة الصيانة

الاختبارات البصرية المبنية على الشفرة (Playwright، Cypress، Selenium) تتطلّب سكريبتات تتنقّل وتتفاعل وتلتقط. وهذه السكريبتات ذاتها تشكّل مصدرًا لعدم الاستقرار: محدّد CSS لم يعد يجد العنصر المستهدف، أو توقيت نقر يُخطئ هدفه.

أدوات بدون شفرة مثل Delta-QA تُزيل طبقة الهشاشة هذه. فأنت لا تكتب سكريبتات — بل تُهيئ اختباراتك بصريًا. والأداة تتولّى التحميل والانتظار والتثبيت والمقارنة. وعندما يتغيّر محدّد عنصر ما، تتكيف الأداة من دون تدخّل.

متى تحذف اختبارًا غير مستقر

إذا فشل اختبار بصري بشكل متقطّع رغم جميع محاولات التثبيت، فإنّ القرار الأشجع — وغالبًا الأحكم — هو حذفه. فالاختبار غير المستقر الذي لا يُصلَح يُقلّل فعلًا من جودة خطّ الأنابيب الخاص بك. وهو يُدرّب فريقك على تجاهل الإخفاقات.

احذفه، ووثّق سبب الحذف، واستبدله بفحص أكثر استهدافًا. الهدف ليس الحصول على أكبر عدد من الاختبارات — بل الحصول على اختبارات يثق بها فريقك.

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

ما الفرق بين الاختبار غير المستقر والإيجابية الكاذبة؟

الإيجابية الكاذبة تُشير إلى مشكلة غير موجودة — وحدوث واحد يكفي. أمّا الاختبار غير المستقر فيُنتج نتائج غير متسقة من تشغيل إلى آخر لنفس الشفرة. فهو يُنتج إيجابيات كاذبة بشكل متقطّع.

كيف تقيس معدّل عدم استقرار اختباراتك البصرية؟

شغّل نفس مجموعة الاختبارات البصرية عدّة مرات من دون تغيير في الشفرة، وعدّ الاختبارات التي تتغيّر نتائجها بين عمليات التشغيل. وخمس عمليات تشغيل متتالية تكفي لتحديد الاختبارات الأكثر عدم استقرارًا.

هل الاختبارات البصرية بدون شفرة أقلّ عدم استقرارًا من الاختبارات المبرمجة؟

تُزيل فئة كاملة من عدم الاستقرار — ألا وهي هشاشة سكريبتات الاختبار (المحددات الهشة، وتوقيت التنقل، وإدارة الحالة). لكنّها لا تزال خاضعة لنفس قيود العرض في المتصفح.

هل يجب إعادة تشغيل الاختبارات البصرية الفاشلة تلقائيًا؟

إعادة المحاولة ضمادة وليست علاجًا. فهي تُخفي المشكلة. وإذا كان لا بدّ من تفعيل إعادة المحاولة، فاقصرها على محاولة واحدة، وضع علامة على الاختبارات التي احتاجت إلى إعادة محاولة لغرض التحقيق.

ما هي عتبة عدم الاستقرار المقبولة في CI/CD؟

استهدف أقلّ من 1 بالمائة من إجمالي مجموعة اختباراتك. وفوق 3 بالمائة، يصبح تأثير الإنتاجية ملحوظًا. وفوق 5 بالمائة، يكاد يكون فريقك قد طوّر بالتأكيد ردّ فعل منهجيًا يتمثّل في إعادة تشغيل خطوط الأنابيب الفاشلة بشكل ممنهج.

هل يُساعد Delta-QA في تثبيت الاختبارات البصرية؟

يُقلّل Delta-QA عدم الاستقرار من مصدره باستخدام نهج هيكلي بدلًا من المقارنة بكسل بكسل. فتباينات العرض تحت البكسل، وتفاوتات مكافحة التعرّج (antialiasing)، ومشاكل التوقيت التي تسبّب معظم حالات الفشل المتقطّع تُتجاهل بطبيعتها. ومقترنًا بنهج بدون شفرة الذي يُلغي سكريبتات الاختبار الهشة، يُنتج Delta-QA نتائج اختبار موثوقة وقابلة للتكرار من دون تهيئة معقّدة.


للمزيد من القراءة


الاختبار البصري لا يملك قيمة إلا إذا كان فريقك يثق به. الاختبارات غير المستقرة تُدمّر تلك الثقة يومًا بعد يوم. فبدلًا من قضاء الوقت في تثبيت سكريبتات هشة وفرز الإخفاقات الكاذبة، تبنَّ أداة مُصمَّمة للموثوقية منذ البداية.

جرّب Delta-QA مجانًا ←