عيوب الانحدار

عيب الانحدار (Regression Defect) عيب يجعل شيئاً كان يعمل قبل تغيير ما يُخفق بعده. ويسمّي مسرد ISTQB النتيجة انحداراً (Regression): تراجعاً في جودة مكوّن أو نظام بسبب تغيير. كان يعمل في إصدار سابق، ويُخفق في إصدار لاحق، وبينهما تغيير: شيفرة جديدة، أو إصلاح، أو ترقية مكتبة، أو إعداد في التهيئة، أو ترحيل للبيانات.

مثال ذلك: يضيف مطوّر فحصاً للرمز البريدي من أجل شركة شحن جديدة، فتبدأ صفحة الدفع، ابتداءً من ذلك البناء، برفض كل عنوان محفوظ بلا رمز بريدي. لم يلمس أحد صفحة الدفع، ومع ذلك تعطّلت.

لماذا يهم

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

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

ما الذي يجعل العيب انحداراً

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

  • المُدخَل (Introduced): التغيير نفسه يحمل الخطأ، كدالة مشتركة عُدّلت من أجل جهة تستدعيها فتعطّلت جهة أخرى.
  • المكشوف (Uncovered): التغيير يُظهر عيباً أقدم كان مخفياً، كإصلاح يسمح للمدخلات بالوصول إلى فحص لم يكن يُنفَّذ من قبل.
  • المُعاد (Reintroduced): عيب أُصلح سابقاً يعود، غالباً بسبب دمج ضاع فيه الإصلاح. وتسمّيه بعض الفرق العيب المتكرر (Recurring Defect).
  • ليس انحداراً: سلوك لم يعمل قط، في ميزة جديدة أو كعيب قديم اكتُشف متأخراً. فهو يُخفق على الإصدار السابق أيضاً.

لماذا يحدث الانحدار

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

  • الشيفرة المشتركة: دالة أو مكوّن أو قاعدة تنسيق أو واجهة برمجية تُستخدم في أماكن عدة، تُغيَّر مع مراعاة واحد منها فقط.
  • الإصلاحات وإعادة الهيكلة (Refactoring): صحيحة للحالة المُبلَّغ عنها، أو يُفترض ألا تغيّر شيئاً، لكنها تغيّر السلوك في حالة حدّية.
  • ترقية المكتبات وأطر العمل والمتصفحات وقاعدة البيانات، وتغييرات التهيئة ومفاتيح الميزات (Feature Flags).
  • البيانات: ترحيل للبيانات، أو قاعدة جديدة تصادف سجلات حُفظت وفق القاعدة القديمة.
  • الدمج والأنظمة المتصلة: تعارض حُلّ بطريقة خاطئة، أو خدمة تغيّر عقدها.

كشف الانحدار: الحزم والمقارنة بالإصدار السليم والتنصيف

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

يضيّق التنصيف (Bisecting) النطاق بين آخر إصدار سليم وأول إصدار معيب إلى تغيير واحد. إنه بحث ثنائي: اختبر الإصدار الواقع في المنتصف، واحتفظ بالنصف الذي تنتقل فيه النتيجة من ناجح إلى فشل، وكرّر. يحتاج ⁦16⁩ بناءً مرشحاً إلى ⁦4⁩ اختبارات على الأكثر، ويحتاج نحو ⁦1000⁩ إيداع (Commit، أي تغيير محفوظ في Git) إلى ⁦10⁩. ويتولى الأمر git bisect هذا التتبّع على الإيداعات، ومن دون الشيفرة المصدرية يمكنك تنصيف أرقام البناء أو الإصدارات في بيئة الاختبار بالطريقة نفسها.

  • استخدم فحصاً موثوقاً: الاختبار المتذبذب يرسل البحث إلى النصف الخطأ.
  • غيّر الإصدار وحده، وأبقِ البيئة والتهيئة والبيانات كما هي.
  • تخطَّ الخطوة التي يتعذّر اختبارها (git bisect skip) بدلاً من التخمين.
  • النتيجة هي أول تغيير يظهر عنده الإخفاق. وقد يكون هذا التغيير كشف عيباً أقدم، فهي دليل للمطور لا اتهام.
git bisect start
git bisect bad                # the version you are on fails
git bisect good v2.7.0        # the last version known to pass
# Git checks out a commit halfway: build it, run the test, then mark it
git bisect good               # or: git bisect bad
# repeat until Git prints "<commit> is the first bad commit"
git bisect reset              # return to where you started

جرّبها: مقارنة استجابات API جرّبها: مقارنة JSON جرّبها: مقارنة النصوص (Diff)

مثال تطبيقي: تنصيف انحدار في صفحة الدفع

ينجح تشغيل الانحدار الليلي على البناء ⁦140⁩ يوم الاثنين، ويفشل على البناء ⁦156⁩ يوم الثلاثاء: فالاختبار TC-311، أي الشراء بعنوان محفوظ بلا رمز بريدي، يتوقف الآن عند الدفع برسالة «العنوان غير مكتمل». وعند إعادة تشغيل TC-311 على البناء ⁦156⁩ يفشل بالطريقة نفسها، وعلى البناء ⁦140⁩، في البيئة نفسها وبالعميل نفسه، ينجح. إذن هذا انحدار، دخل في أحد البناءات من ⁦141⁩ إلى ⁦156⁩، ويتضمن كل منها تغييراً واحداً مدموجاً.

تكفي أربعة اختبارات للعثور عليه. لا يتضمن البناء ⁦147⁩ إلا PR-882، الذي أضاف إلى الدالة المشتركة validateAddress() فحصاً يجعل الرمز البريدي إلزامياً من أجل شركة الشحن الجديدة: صحيح للعناوين الجديدة، وخاطئ لكل عنوان حُفظ قبله. وقد نجحت فحوص طلب الدمج (Pull Request) لأن بيانات اختبارها لم تحوِ إلا عناوين جديدة.

تنصيف انحدار الشراء بالعنوان المحفوظ: أربعة تشغيلات للاختبار TC-311 تضيّق الأبنية من ⁦141⁩ إلى ⁦156⁩ حتى البناء ⁦147⁩، أول بناء يفشل فيه.

رقم البناء، الاختبار TC-311

المحور من 140 إلى 156
  • 140–146سليم: ينجح TC-311
  • 147–156معيب: يفشل TC-311 ابتداءً من البناء ⁦147⁩
  1. 1140 التشغيل الليلي يوم الاثنين: آخر بناء سليم معروفإعادة التشغيل في البيئة نفسها: ينجحنجاح
  2. 2156 التشغيل الليلي يوم الثلاثاء: بناء معيب معروفإعادة التشغيل: يفشل بالطريقة نفسهافشل
  3. 3148 اختبار التنصيف ⁦1⁩النطاق التالي: ⁦141–148⁩فشل
  4. 4144 اختبار التنصيف ⁦2⁩النطاق التالي: ⁦145–148⁩نجاح
  5. 5146 اختبار التنصيف ⁦3⁩النطاق التالي: ⁦147–148⁩نجاح
  6. 6147 اختبار التنصيف ⁦4⁩: أول بناء معيبيتضمن تغييراً واحداً: PR-882فشل
  • عنوان التقرير: «صفحة الدفع ترفض العناوين المحفوظة بلا رمز بريدي (انحدار منذ البناء ⁦147⁩)».
  • الدليل: آخر بناء سليم ⁦146⁩، وأول بناء معيب ⁦147⁩، والتغيير المشتبه به PR-882، وكشفه TC-311 في التشغيل الليلي.
  • يطبّق الإصلاح الفحص على شركة الشحن الجديدة فقط، ويُضاف TC-311 إلى فحوص طلبات الدمج.
النسخة النصية
Known good: build 140   Monday nightly run, TC-311 passed
Known bad:  build 156   Tuesday nightly run, TC-311 failed
Candidates: builds 141..156, one merged change each (16 builds)

Test  Build  TC-311  First bad build is in
1     148    fail    141..148
2     144    pass    145..148
3     146    pass    147..148
4     147    fail    147  -> first bad build

Build 147 contains one change: PR-882 "Require postcode for new courier"

منع الانحدار

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

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

    بوابة: دُمج

  3. 3التشغيل الليلي على الفرع الرئيسيحزمة الانحدار الكاملة · تغييرات يوم للبحث فيها
  4. 4انحدار الإصداراختبارات الانحدار والاختبار الاستكشافي · تغييرات الإصدار قبل أن يراها المستخدمون

    بوابة: صدر الإصدار

  5. 5الإنتاجيبلّغ عنه المستخدمون · تغييرات الإصدار بعد أن تضرّر المستخدمون

أبكر: تغييرات أقل بين آخر سليم وأول معيبلاحقاً: تغييرات أكثر للبحث فيها، ومستخدمون متضررون

توضيحي: تختلف الفرق في تسمية هذه التشغيلات وفي الجمع بينها.

  • أجرِ تحليلاً سريعاً للأثر (Impact Analysis) قبل الدمج: من يستخدم هذه الشيفرة أيضاً؟ وأي بيانات مخزنة تصادف القاعدة الجديدة؟
  • شغّل اختبارات الانحدار المتصلة بالتغيير، مختارةً حسب الأثر والمخاطر، على كل طلب دمج، والحزمة الكاملة على الفرع الرئيسي، بوصفها بوابة جودة قادرة على إيقاف التغيير.
  • احتفظ ببيانات اختبار تشبه تاريخ الإنتاج: سجلات قديمة، وحقول اختيارية فارغة، وبيانات حُفظت وفق قواعد سابقة.
  • لكل انحدار يُصلَح، أضف الاختبار الذي كان سيكشفه، في أدنى مستوى يمكنه التعبير عنه.
  • أصلح الاختبارات المتذبذبة أو اعزلها، لكي يعني التشغيل الأحمر شيئاً دائماً.
  • فضّل التغييرات الصغيرة، ورقِّ المكتبات في تغيير مستقل مع تشغيل للانحدار؛ فالتغييرات الصغيرة أسهل في المراجعة وفي التنصيف.

جرّبها: مولّد سيناريوهات الانحدار جرّبها: مولّد الاختبار المبني على المخاطر

أخطاء شائعة

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

من منظور ضمان الجودة

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

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

تمرين عملي

صنّف انحدار إصدار ونصّفه وأبلغ عنه

المطلوب

يُختبر الإصدار ⁦3.1⁩ مقارنةً بالإصدار ⁦3.0⁩ (البناء ⁦200⁩) الموجود في الإنتاج. ويتضمن كل بناء من ⁦201⁩ إلى ⁦232⁩ تغييراً واحداً مدموجاً. وأنتجت دورة الاختبار البلاغات الثلاثة أدناه.

حدّد أيها انحدار، وخطّط للتنصيف، واكتب حقول الانحدار في تقرير الخطأ، واقترح إجراءين للمنع.

المادة
مرشّح الإصدار 3.1: البناء 232. الإصدار 3.0 في الإنتاج: البناء 200.
كل بناء من 201 إلى 232 يتضمن تغييراً واحداً مدموجاً.

A  TC-540  البحث عن "cafe" يجد المنتج "Café Latte"
           البناء 200: ناجح     البناء 232: فشل
B  جديد في 3.1: «التصفية حسب العلامة التجارية» تعرض العلامات بترتيب عشوائي
C  تاريخ الميلاد 29/02/2000 لا يمكن حفظه في الملف الشخصي
           البناء 232: فشل     الإصدار 3.0 في الإنتاج: فشل
الخطوات
  1. صنّف A وB وC، واذكر الدليل الذي يحسم كلاً منها.
  2. كم اختبار تنصيف تحتاج على الأكثر؟ وأي بناء تختبر أولاً، وأيّه بعده إن نجح أو فشل؟
  3. ينتهي التنصيف عند البناء ⁦219⁩، الذي لا يتضمن إلا ترقية مكتبة البحث. اكتب العنوان وآخر بناء سليم وأول بناء معيب والتغيير المشتبه به والاختبار الذي كشفه.
  4. اقترح إجراءين للمنع.
إظهار الإجابة النموذجية
الإجابة النموذجية

A انحدار: ينجح TC-540 على البناء ⁦200⁩ ويفشل على ⁦232⁩. وB ليس انحداراً: الميزة جديدة في ⁦3.1⁩ ولم تعمل قط. وC ليس انحداراً كذلك: يفشل في الإصدار ⁦3.0⁩ أيضاً، فهو عيب قديم اكتُشف متأخراً. ويُبلَّغ عن B وC دون وسم الانحدار.

يحتاج ⁦32⁩ بناءً إلى ⁦5⁩ اختبارات على الأكثر. اختبر ⁦216⁩ أولاً؛ فإن نجح فاختبر ⁦224⁩ (النطاق من ⁦217⁩ إلى ⁦232⁩)، وإن فشل فاختبر ⁦208⁩ (النطاق من ⁦201⁩ إلى ⁦216⁩). وأبقِ البيئة والبيانات كما هي.

العنوان: «البحث لم يعد يطابق أسماء المنتجات التي فيها حروف بعلامات مثل é (انحدار منذ البناء ⁦219⁩)». آخر بناء سليم ⁦218⁩، وأول بناء معيب ⁦219⁩، والتغيير المشتبه به ترقية مكتبة البحث، وكشفه TC-540. وقد تكون الترقية غيّرت إعداداً افتراضياً، كطريقة مقارنة الحروف ذات العلامات، لا أنها تحمل عيباً؛ والمطور هو من يحسم ذلك.

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

أسئلة شائعة

هل كل عيب يُكتشف أثناء اختبار الانحدار عيبُ انحدار؟

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

هل أحتاج إلى معرفة Git لأقوم بالتنصيف؟

لا. التنصيف طريقة لا أمر: يمكنك تطبيقه على أرقام البناء في بيئة الاختبار، أو على الإصدارات، أو على مجموعة تغييرات تُفعَّل بمفاتيح الميزات. والأمر git bisect يؤتمته على الإيداعات، وgit bisect run يكرر الخطوات بنص برمجي (Script) يحسم رمز خروجه (Exit Code) النتيجة: ⁦0⁩ يعني سليماً، و⁦125⁩ يعني التخطي، وباقي القيم من ⁦1⁩ إلى ⁦127⁩ تعني معيباً.

هل يجب أن يحصل الانحدار دائماً على أولوية أعلى؟

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

حين يعود عيب أُصلح سابقاً، هل أعيد فتح العيب القديم؟

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

المراجع

  • ISTQB Certified Tester Foundation Level (CTFL) v4.0ISTQB · 2023المنهج التأسيسي لاختبار البرمجيات: مستويات الاختبار وأنواعه وتقنيات تصميم الاختبارات وإدارة الاختبار والأدوات.
  • ISTQB GlossaryISTQBالتعريفات القياسية لمصطلحات الاختبار — حالة الاختبار واختبار الانحدار والخطورة والأولوية وتحليل القيم الحدّية وغيرها.
  • Reference — GitGit projectالمرجع الرسمي لكل أوامر Git وخياراتها، مجمّعةً حسب المهمة — الإعداد والتفريع والمشاركة وتطبيق الرقع والفحص وتتبّع الأخطاء.
  • Continuous Integration (Martin Fowler)martinfowler.com · 2024الوصف الأكثر استشهاداً للتكامل المستمر: ادمج كثيراً، واجعل البناء يختبر نفسه وسريعاً، وأصلح البناء المكسور فوراً.

تدرّب بأدوات متقن

قارن استجابتي API (مثل بيئة التجريب مقابل الإنتاج) واحصل على قائمة بكل فرق بنيوي أو في القيم.

اختبار واجهات API

مقارنة مستندي JSON دلالياً وإبراز القيم المضافة والمحذوفة والمتغيرة.

JSON والبيانات

للتعمّق أكثر

تقدّمك في هذا الموضوع

جزء من مسار تعلم ضمان الجودة