تغطية الاختبار

تغطية الاختبار (Test Coverage) هي مقدار ما شغّلته اختباراتك فعلاً من مجموعة محددة من الأشياء. ويسمّي مسرد ISTQB هذه الأشياء بنود التغطية (Coverage Items)، ويعبّر عن التغطية بنسبة مئوية. مثال: قصة مستخدم لها ⁦8⁩ معايير قبول، تحقّق اختبارٌ نُفّذ على البناء (Build) الحالي من ستةٍ منها، فتغطية معايير القبول ⁦6⁩ من ⁦8⁩، أي ⁦75%⁩.

والسؤال الأول دائماً هو: «تغطية ماذا؟». فالمتطلبات والمخاطر والشيفرة تُغطّى وتُقاس بطرق مختلفة، ويتولاها في الغالب أشخاص مختلفون، ولكل منظور نقاطه العمياء. التغطية تُظهر مقدار ما شغّلته الاختبارات من القائمة، ولا تُثبت أبداً أن البرنامج خالٍ من العيوب.

لماذا يهم

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

أما بالنسبة إلى المختبِر، فالتغطية تحوّل الجهد إلى عبارة يستطيع الآخرون التحقق منها والعمل بها: «لكل معايير القبول الـ⁦14⁩ اختبارات ناجحة، ولم يُختبر خطران متوسطان لأن بيئة الدفع التجريبية كانت متوقفة». وهي أيضاً ما يجعل معايير الخروج قابلة للقياس، ويحمي الفريق من ثقة زائفة برقم واحد كبير.

تغطية ماذا؟ المتطلبات والمخاطر والشيفرة

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

  • تغطية المتطلبات (Requirements Coverage): أيّ المتطلبات أو معايير القبول لها اختبارات، وأيّها لها اختبارات ناجحة. وبنود التغطية هنا هي المعايير الموجودة في أساس الاختبار، وتُعدّ عبر التتبّع (Traceability): ربط كل اختبار بالمعيار الذي يتحقق منه.
  • تغطية المخاطر (Risk Coverage): أيّ مخاطر المنتج المحددة لها اختبارات نُفّذت، وأيّها لها اختبارات نجحت، مع عرضها حسب مستوى الخطر. فعبارة «الخطران العاليان مُختبَران واختباراتهما ناجحة، و⁦2⁩ من ⁦5⁩ مخاطر متوسطة لم تُختبر بعد» تدعم قرار الإصدار أفضل من أي نسبة مئوية منفردة.
  • تغطية الشيفرة (Code Coverage): أيّ أجزاء الشيفرة جرى تشغيلها أثناء الاختبارات، وتقيسها أداة. فتغطية التعليمات (Statement Coverage) تعدّ التعليمات القابلة للتنفيذ، وتغطية الفروع (Branch Coverage) تعدّ الفروع، أي انتقالات التحكم في الشيفرة، وتعرضها أدوات التغطية على أنها نتائج القرارات، مثل جانبَي جملة if. وتغطية الفروع أقوى: فتغطية الفروع بنسبة ⁦100%⁩ تتضمن تغطية التعليمات بنسبة ⁦100%⁩، والعكس غير صحيح.

بنود التغطية وكيف تقيسها

يقيس منهج ISTQB للمستوى التأسيسي (الإصدار ⁦4.0⁩) التغطية من خلال بنود التغطية: أشياء يمكن عدّها، تُستخرج من شروط الاختبار بتطبيق تقنية اختبار، كما في درس نشاط تصميم الاختبار. يحدّدها تصميم الاختبار، ويشغّلها التنفيذ. والمعادلة لا تتغيّر: coverage = items exercised ÷ items identified × 100%، أي البنود التي شُغِّلت مقسومةً على البنود المحددة.

اذكر الأعداد مع النسبة («⁦9⁩ من ⁦12⁩ معياراً») والبناء الذي تنطبق عليه. وفي تعريف ISTQB يُعدّ البند مغطّى بمجرد أن يشغّله اختبار، أياً كانت النتيجة، لذا قدّم في المتطلبات والمخاطر رقمين: البنود التي لها اختبار نُفّذ على ذلك البناء، والبنود التي نجحت اختباراتها. والرقم الثاني وحده يقول إن البند يعمل: فالاختبار الفاشل يترك بنده مفتوحاً، والاختبار المحجوب أو غير المنفَّذ لم يشغّل شيئاً بعد. وتأتي تغطية المتطلبات والمخاطر من روابط التتبّع في أداة إدارة الاختبار أو في مصفوفة التتبّع، أما تغطية الشيفرة فتأتي من أداة تضيف نقاط رصد إلى الشيفرة (Instrumentation) أثناء تشغيل الاختبارات، وغالباً في خط التكامل المستمر (CI). وما يتغيّر من منظور أو تقنية إلى أخرى هو البند:

  • المتطلبات: معايير القبول أو المتطلبات منفردةً.
  • المخاطر: المخاطر المحددة، مجمّعةً حسب مستوى الخطر.
  • تقسيم التكافؤ (Equivalence Partitioning): الأقسام. تحليل القيم الحدّية (Boundary Value Analysis): القيم الحدّية.
  • جداول القرار: الأعمدة التي تحوي تركيبات ممكنة من الشروط.
  • انتقالات الحالة: الحالات، أو الانتقالات الصالحة، أو جميع الانتقالات.
  • الشيفرة: التعليمات القابلة للتنفيذ، أو الفروع (في أدوات التغطية: كل نتيجة لكل قرار).

جرّبها: المتطلبات ← حالات اختبار جرّبها: مولّد انتقالات الحالات

مثال تطبيقي: أربعة أرقام تغطية لميزة واحدة

ميزة في صفحة الدفع تطبّق رمز خصم. معايير القبول: AC1، الرمز الصالح يخفّض الإجمالي بنسبته؛ AC2، الرمز المنتهي يُرفض برسالة واضحة؛ AC3، الرموز لا تنطبق إلا على إجمالي ⁦100.00⁩ ريال فأكثر؛ AC4، رمز واحد لكل طلب. ومخاطر المنتج: R1 (عالٍ) تطبيق الرمز مرتين على طلب واحد؛ R2 (عالٍ) قبول رمز منتهي الصلاحية؛ R3 (متوسط) تطبيق حدّ ⁦100.00⁩ على الجانب الخطأ.

كتب المطور اختبار وحدة واحداً لدالة الخصم، ونفّذ المختبِر ثلاثة اختبارات نظام على البناء ⁦57⁩، يفحص فيها TC-03 الإجماليين ⁦99.99⁩ و⁦100.00⁩. والشيفرة والتقارير أدناه. وهذا ما يقوله كل رقم:

ميزة خصم واحدة وأربعة أرقام تغطية: تبلغ اختبارات الوحدة ⁦100%⁩ في تغطية التعليمات و⁦50%⁩ في تغطية الفروع، بينما لا يوجد اختبار ناجح إلا لمعيارين من ⁦4⁩ معايير قبول ولخطر واحد من ⁦3⁩ مخاطر.
  • مغطّى باختبار ناجح
  • اختباره الوحيد فشل
  • غير مغطّى، بلا اختبار
  • تغطية التعليمات (اختبارات الوحدة)⁦4⁩ من ⁦4⁩ تعليمات، ⁦100%⁩
    • 4 مغطّى باختبار ناجح
    • 0 اختباره الوحيد فشل
    • 0 غير مغطّى، بلا اختبار
  • تغطية الفروع (اختبارات الوحدة)فرع واحد من ⁦2⁩، ⁦50%⁩
    • 1 مغطّى باختبار ناجح
    • 0 اختباره الوحيد فشل
    • 1 غير مغطّى، بلا اختبار
  • معايير القبول (اختبارات النظام)⁦2⁩ من ⁦4⁩ لها اختبار ناجح، ⁦50%⁩
    • 2 مغطّى باختبار ناجح
    • 1 اختباره الوحيد فشل
    • 1 غير مغطّى، بلا اختبار
  • مخاطر المنتج (اختبارات النظام)خطر واحد من ⁦3⁩ له اختبار ناجح، ولا شيء من الخطرين العاليين
    • 1 مغطّى باختبار ناجح
    • 1 اختباره الوحيد فشل
    • 1 غير مغطّى، بلا اختبار

في الشيفرة يُعدّ البند مغطّى إذا نُفّذ مرة واحدة على الأقل أثناء اختبار الوحدة الناجح؛ وفي المعايير والمخاطر إذا نجح اختبار نظام مرتبط بها على البناء ⁦57⁩. أما الاختبار الفاشل فقد شغّل بنده لكنه يتركه مفتوحاً.

  • تغطية التعليمات ⁦100%⁩ (⁦4⁩ من ⁦4⁩): نُفّذت كل تعليمة في applyDiscount أثناء اختبار الوحدة، ومع ذلك لم يجرّب أي اختبار وحدة إجمالياً أقل من ⁦100.00⁩.
  • تغطية الفروع ⁦50%⁩ (⁦1⁩ من ⁦2⁩): النتيجة false للشرط total >= 100 لم تُنفَّذ قط. واختبار وحدة بإجمالي ⁦99.99⁩ يغطيها.
  • معايير القبول: ⁦3⁩ من ⁦4⁩ لها اختبار (⁦75%⁩)، لكن ⁦2⁩ فقط من ⁦4⁩ لها اختبار ناجح (⁦50%⁩). فقد فشل TC-02، وليس لـAC4 أي اختبار.
  • المخاطر: خطران من ⁦3⁩ لهما اختبار، لكنّ خطراً واحداً فقط من ⁦3⁩ له اختبار ناجح، وليس لأيٍّ من الخطرين العاليين اختبار ناجح: فلا اختبار لـR1، واختبار R2 فشل. وهذا هو الرقم الذي يحتاجه قرار الإصدار.
  • لا شيء في applyDiscount يعالج «رمز واحد لكل طلب». فإن لم يُنفَّذ AC4 أصلاً، فلن يكشف ذلك أيُّ تقرير لتغطية الشيفرة: فالأداة لا تقيس إلا شيفرة موجودة.
// discount.ts
export function applyDiscount(total: number, percent: number): number {
  let result = total;
  if (total >= 100) {
    result = total - (total * percent) / 100;
  }
  return result;
}

// discount.test.ts (Jest): the only unit test
import { applyDiscount } from './discount';

test('10% off an order of 150', () => {
  expect(applyDiscount(150, 10)).toBe(135);
});

Code coverage (unit tests)   Statements   Branches
discount.ts                  4/4  100%    1/2  50%

Traceability, system tests on build 57
Criterion   Test     Result     Risk
AC1         TC-01    passed     -
AC2         TC-02    failed     R2 (high)
AC3         TC-03    passed     R3 (medium)
AC4         -        no test    R1 (high)

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

لماذا لا تعني تغطية ⁦100%⁩ خلوّ البرنامج من العيوب

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

  • المقام لا يضم إلا ما حدّدته. فالمتطلب المفقود أو الخطر غير المدرج لا يظهر في النسبة أبداً، لذا تبقى تغطية ⁦100%⁩ لقائمة ناقصة تغطيةً ناقصة.
  • التنفيذ ليس تحققاً. فاختبار بلا تأكيد (Assertion)، أي بلا فحص للناتج، يستدعي applyDiscount(150, 10) يعطي تغطية التعليمات نفسها ⁦100%⁩ التي يعطيها اختبار يتحقق من أن الناتج ⁦135⁩.
  • البيانات مهمة. فالاستدعاء applyDiscount(150, 110) يُعيد إجمالياً سالباً، ولن تكشف ذلك تغطية الفروع الكاملة. ومثال المنهج نفسه قسمةٌ لا تُخفق إلا حين يكون المقسوم عليه صفراً.
  • تغطية الشيفرة لا ترى الإغفال: فالشيفرة التي لم تُكتب أصلاً ليس فيها تعليمات تفوتك.
  • قد يتحوّل الهدف إلى لعبة: فيضيف الناس اختبارات تشغّل الشيفرة دون أن تتحقق من شيء. ومراجعة التأكيدات، أو اختبار الطفرات (Mutation testing)، أي تغييرات صغيرة متعمدة في الشيفرة يجب أن تكشفها حزمة اختبارات جيدة، تساعد على معرفة ما إذا كانت الشيفرة المغطّاة يُتحقق منها فعلاً.

جرّبها: محلّل تغطية الاختبار بالذكاء الاصطناعي

أخطاء شائعة

  • الإبلاغ بأن «التغطية ⁦85%⁩» دون ذكر تغطية ماذا، وعلى أي بناء، ومن أصل كم بنداً.
  • الإبلاغ عن معيار أو خطر بأنه منجَز لمجرد وجود اختبار له، مع أن هذا الاختبار فشل أو حُجب أو لم يُنفَّذ على البناء الحالي.
  • اعتبار تغطية الشيفرة بنسبة ⁦100%⁩ دليلاً على صحة الشيفرة، أو مطاردة النسبة باختبارات لا تتحقق من شيء.
  • نسيان أن المتطلبات المفقودة والمخاطر غير المدرجة ليست في المقام، فلا تستطيع أي نسبة أن تكشفها.
  • اعتبار اختبار سطحي واحد تغطيةً كاملة لبند عالي الخطورة: فالتغطية تعدّ البنود، لا مدى عمق اختبار كل بند.

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

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

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

تمرين عملي

احسب التغطية وأبلغ عنها لقصة إعادة تعيين كلمة المرور

المطلوب

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

المادة
القصة: إعادة تعيين كلمة المرور عبر رابط بالبريد الإلكتروني

AC1  الضغط على «نسيت كلمة المرور» يرسل رابط إعادة تعيين إلى بريد مسجَّل.
AC2  البريد غير المسجَّل يتلقى الرسالة المحايدة نفسها التي يتلقاها المسجَّل.
AC3  تنتهي صلاحية الرابط بعد 30 دقيقة من إرساله.
AC4  لا يمكن استخدام الرابط إلا مرة واحدة.
AC5  يجب أن يكون طول كلمة المرور الجديدة من 12 إلى 64 حرفاً.

المخاطر
R1  AC3, AC4  عالٍ: يمكن إعادة استخدام الرابط أو لا تنتهي صلاحيته أبداً
R2  AC2       عالٍ: الرسالة تكشف أيّ العناوين لها حسابات
R3  AC5       متوسط: قاعدة كلمة المرور غير مطبَّقة

اختبارات النظام على البناء 112
TC-01  AC1  ناجح
TC-02  AC1  ناجح
TC-03  AC2  ناجح
TC-04  AC3  فشل
TC-05  AC5  ناجح

اختبارات الوحدة، reset-service.ts
تغطية التعليمات 96%
تغطية الفروع 71%
الخطوات
  1. اربط كل معيار باختباراته ونتائجها.
  2. احسب تغطية المعايير مرتين: بأي اختبار نُفّذ، وباختبار ناجح.
  3. احسب تغطية المخاطر، منفصلةً للمخاطر العالية والمتوسطة.
  4. فسّر أرقام اختبارات الوحدة، ثم اكتب العبارة وخطواتك التالية.
إظهار الإجابة النموذجية
الإجابة النموذجية

المعايير: AC1 (TC-01 وTC-02 ناجحان)، وAC2 (TC-03 ناجح)، وAC3 (TC-04 فشل)، وAC4 (بلا اختبار)، وAC5 (TC-05 ناجح). التي لها اختبار: ⁦4⁩ من ⁦5⁩ (⁦80%⁩). والتي لها اختبار ناجح: ⁦3⁩ من ⁦5⁩ (⁦60%⁩)، وهو الرقم الذي يُعتدّ به عند الإصدار.

المخاطر: لكلٍّ من R2 (عالٍ) وR3 (متوسط) اختبارات ناجحة. أما R1 (عالٍ) فليس له: فاختبار انتهاء الصلاحية فشل، والاستخدام لمرة واحدة بلا اختبار. أي خطران من ⁦3⁩، وخطر متوسط واحد من ⁦1⁩، لكن خطر عالٍ واحد فقط من ⁦2⁩.

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

العبارة: «إعادة تعيين كلمة المرور، البناء ⁦112⁩: لـ⁦3⁩ من ⁦5⁩ معايير قبول اختبار ناجح (⁦60%⁩). الخطر العالي R1 مفتوح: فشل اختبار انتهاء الصلاحية TC-04، والاستخدام لمرة واحدة (AC4) لم يُختبر بعد؛ أما R2 وR3 فلهما اختبارات ناجحة. وتبلغ اختبارات الوحدة ⁦96%⁩ في تغطية التعليمات و⁦71%⁩ في تغطية الفروع، ولم تُراجَع الفروع غير المغطّاة بعد».

الخطوات التالية: اختبر AC4؛ وأبلغ عن فشل TC-04 كعيب وأعد اختباره بعد الإصلاح (اختبار التأكيد)؛ وأضف اختبارات لـAC5 على جانبَي كل حدّ (⁦11⁩ و⁦12⁩ و⁦64⁩ و⁦65⁩ حرفاً)، لأن اختباراً ناجحاً واحداً يغطي المعيار عدّاً لا عمقاً.

أسئلة شائعة

هل تغطية الاختبار هي نفسها تغطية الشيفرة؟

لا. تغطية الاختبار هي الفكرة العامة: نسبة بنود التغطية المحددة التي شغّلتها الاختبارات. وتغطية الشيفرة نوع منها، بنودها التعليمات أو الفروع. ومن أنواعها الأخرى تغطية المتطلبات، وتغطية المخاطر، وتغطية تقنية اختبار ما (الأقسام، والقيم الحدّية، والانتقالات).

ما النسبة الجيدة لتغطية الشيفرة؟

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

من يقيس تغطية الشيفرة: المطورون أم المختبِرون؟

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

إذا بلغنا ⁦100%⁩ من هدف التغطية، فهل نتوقف عن الاختبار؟

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

المراجع

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

حوّل قائمة متطلبات مرقّمة إلى حالات اختبار قابلة للتتبّع مع مصفوفة تربط المتطلبات بالاختبارات.

تصميم الاختبارات

عرّف الحالات والأحداث، ثم ولّد جدول الانتقالات واختبارات الانتقالات الصالحة/غير الصالحة وتغطية 0-switch/1-switch.

تصميم الاختبارات

للتعمّق أكثر

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

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