تغطية الكود (Code Coverage)

الكاتب: قالب اقرأتاريخ النشر: آخر تحديث: وقت القراءة:
للقراءة
عدد الكلمات:
كلمة
عدد التعليقات: 0 تعليق
نبذة عن المقال: تعلم مفهوم تغطية الكود (Code Coverage) وأهميته في اختبار البرمجيات. اكتشف كيفية إنشاء وتحليل تقارير التغطية باستخدام Vitest لتحسين جودة اختباراتك.

مرحباً بك في درس جديد! 

بعد أن تعلمنا كيفية كتابة الاختبارات وتشغيلها، حان الوقت لنسأل سؤالاً مهماً: "كيف نعرف أن اختباراتنا تغطي أجزاء الكود المهمة؟ وهل هناك أجزاء من تطبيقنا لم يتم اختبارها بعد؟" هنا يأتي دور "تغطية الكود" أو الـ Code Coverage.

تخيل أنك تبني منزلاً كبيراً، وبعد انتهاء البناء، يأتي مفتش الجودة. هل سيكتفي بالنظر إلى المنزل من الخارج ويقول "يبدو جيداً"؟ بالطبع لا. سيقوم بالدخول إلى كل غرفة، وفحص كل زاوية، والتأكد من أن كل جزء من المنزل مطابق للمواصفات. الـ Code Coverage هو مفتش الجودة الخاص بكودك.

في هذا الدرس، سنتعمق في مفهوم تغطية الكود، ونتعلم كيف يمكن أن يساعدنا في كتابة اختبارات أفضل وزيادة ثقتنا في الكود الذي نكتبه.

تغطية الكود (Code Coverage)

ما هي تغطية الكود (Code Coverage)؟

ببساطة، Code Coverage هو مقياس يُستخدم لتحديد نسبة الكود المصدري الذي تم تنفيذه أثناء تشغيل مجموعة الاختبارات. يتم التعبير عن هذا المقياس عادةً كنسبة مئوية. إذا كانت تغطية الكود لديك 80%، فهذا يعني أن 80% من كودك قد تم "زيارته" أو تنفيذه بواسطة اختباراتك، بينما الـ 20% المتبقية لم يتم لمسها على الإطلاق.

هذا المقياس يساعدنا على:

  1. اكتشاف الأجزاء غير المختبرة: يبرز لك بوضوح الأجزاء، الدوال، أو الشروط المنطقية في الكود التي لا تغطيها أي اختبارات.
  2. زيادة الثقة: كلما ارتفعت نسبة التغطية، زادت ثقتك في أن تغييراتك المستقبلية لن تكسر وظائف موجودة دون أن تلاحظ.
  3. تحسين جودة الاختبارات: يشجعك على التفكير في الحالات الحافة (Edge Cases) والمسارات المختلفة داخل دوالك التي ربما تكون قد أغفلتها.

مقاييس تغطية الكود الرئيسية

عندما تقوم بتشغيل تقرير تغطية الكود، سترى عادةً أربعة مقاييس رئيسية:

  1. تغطية الأسطر (Line Coverage): أبسط أنواع المقاييس. هل تم تنفيذ كل سطر من أسطر الكود القابلة للتنفيذ مرة واحدة على الأقل؟
  2. تغطية الدوال (Function Coverage): هل تم استدعاء كل دالة في الكود مرة واحدة على الأقل؟
  3. تغطية الفروع (Branch Coverage): هذا المقياس أكثر دقة. بالنسبة لكل بنية شرطية (مثل if, switch, أو ternary operator)، هل تم اختبار كل فرع من فروعها المنطقية؟ على سبيل المثال، في جملة if/else، هل قمت باختبار ما يحدث عندما يكون الشرط true وما يحدث عندما يكون false؟
  4. تغطية الجمل (Statement Coverage): هل تم تنفيذ كل جملة برمجية (statement) في الكود؟ هذا المقياس شبيه بتغطية الأسطر، ولكنه أكثر دقة في بعض الحالات حيث يمكن أن يحتوي السطر الواحد على أكثر من جملة برمجية.

ملاحظة هامة

تغطية الفروع (Branch Coverage) تعتبر من أهم المقاييس، لأن الحصول على تغطية 100% للأسطر لا يضمن أنك اختبرت جميع المسارات المنطقية الممكنة في الكود الخاص بك.

إنشاء تقرير تغطية الكود مع Vitest

لحسن الحظ، Vitest يجعل من السهل جداً إنشاء تقارير تغطية الكود. يستخدم Vitest أداة تسمى v8 (محرك JavaScript الخاص بـ Node.js و Chrome) بشكل افتراضي لجمع بيانات التغطية، وهي سريعة جداً ولا تتطلب أي إعدادات إضافية.

لتشغيل اختباراتك مع تفعيل تقرير التغطية، كل ما عليك فعله هو إضافة خيار --coverage إلى أمر التشغيل:

CODE
npx vitest run --coverage

عند تشغيل هذا الأمر، سيقوم Vitest بتنفيذ جميع اختباراتك كالمعتاد، ولكنه في النهاية سيقوم بطباعة جدول ملخص لتغطية الكود في الـ terminal. بالإضافة إلى ذلك، سيقوم بإنشاء مجلد جديد باسم coverage في مشروعك يحتوي على تقرير HTML تفاعلي.

تحليل تقرير تغطية الكود

لنفترض أن لدينا الدالة التالية في ملف user.js التي تحسب سعر التذكرة بناءً على عمر المستخدم:

JavaScript
// user.js
export function getTicketPrice(age) {
  if (age < 18) {
    return 10; // Price for minors
  }
  if (age >= 65) {
    return 15; // Price for seniors
  }
  return 20; // Standard price
}

والآن، لنكتب اختبارًا واحدًا فقط في user.test.js:

JavaScript
// user.test.js
import { describe, it, expect } from 'vitest';
import { getTicketPrice } from './user';

describe('getTicketPrice', () => {
  it('should return the standard price for an adult', () => {
    // Testing the standard price for a 30-year-old adult
    expect(getTicketPrice(30)).toBe(20);
  });
});

الآن، لنقم بتشغيل الأمر npx vitest run --coverage. سترى شيئًا مشابهًا لهذا في الـ terminal:

CODE
----------------|---------|----------|---------|---------|-------------------
File            | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------------|---------|----------|---------|---------|-------------------
All files       |   83.33 |       50 |     100 |   83.33 |                   
 user.js        |   83.33 |       50 |     100 |   83.33 | 4,7               
----------------|---------|----------|---------|---------|-------------------

لاحظ أن نسبة تغطية الفروع (% Branch) هي 50% فقط! لماذا؟ لأن اختبارنا يغطي فقط حالة الشخص البالغ (العمر 30)، لكنه لم يختبر حالة القاصر (age < 18) أو حالة كبير السن (age >= 65).

للحصول على رؤية أفضل، افتح ملف index.html الموجود داخل مجلد coverage الذي تم إنشاؤه. ستجد تقريرًا تفصيليًا. عند النقر على user.js، سترى الكود الخاص بك مع تمييز الأسطر:

  • الأسطر الخضراء: تم تغطيتها.
  • الأسطر الحمراء: لم يتم تغطيتها.
  • علامة I الصفراء: تعني أن فرع if لم يتم اختباره (تم اختبار else فقط).
  • علامة E الصفراء: تعني أن فرع else لم يتم اختباره.

في مثالنا، ستجد أن السطرين return 10; و return 15; باللون الأحمر، لأنه لم يتم الوصول إليهما أبدًا.

لحل هذه المشكلة وتحقيق تغطية 100%، نحتاج إلى إضافة اختبارات تغطي هذه الحالات:

JavaScript
// user.test.js (updated)
import { describe, it, expect } from 'vitest';
import { getTicketPrice } from './user';

describe('getTicketPrice', () => {
  it('should return the standard price for an adult', () => {
    expect(getTicketPrice(30)).toBe(20);
  });

  it('should return the discounted price for a minor', () => {
    expect(getTicketPrice(15)).toBe(10);
  });

  it('should return the discounted price for a senior', () => {
    expect(getTicketPrice(70)).toBe(15);
  });
});

الآن، إذا قمت بتشغيل npx vitest run --coverage مرة أخرى، سترى أن جميع المقاييس وصلت إلى 100%.

خرافة تغطية الكود 100%

تحذير

السعي الأعمى لتحقيق نسبة 100% في تغطية الكود يمكن أن يكون مضللاً وله نتائج عكسية. تغطية الكود العالية لا تعني بالضرورة أن اختباراتك جيدة.

من الممكن أن يكون لديك تغطية 100% ولكن اختباراتك سيئة. كيف؟ قد يقوم اختبارك بتنفيذ سطر من الكود، ولكنه لا يتحقق من السلوك الصحيح ( أي لا يحتوي على assertion جيد).

مثال على اختبار سيء بتغطية 100%:

JavaScript
it('should run without crashing', () => {
  // This test executes the function, contributing to coverage.
  const price = getTicketPrice(15);
  // But it doesn't assert the actual outcome!
  // It only checks if the function returns *something*.
  expect(price).toBeDefined(); 
});

هذا الاختبار سيساهم في تغطية الكود، لكنه لا يضمن أن الدالة تعيد القيمة الصحيحة (10). كان من الممكن أن تعيد الدالة القيمة 20 وسيظل الاختبار ناجحًا.

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

خلاصة الدرس

في هذا الدرس، تعلمنا عن مفهوم Code Coverage وأهميته.

  • تغطية الكود هي مقياس يوضح نسبة الكود الذي تم تنفيذه بواسطة اختباراتك.
  • تساعدنا على إيجاد الثغرات في مجموعة اختباراتنا وزيادة الثقة في الكود.
  • المقاييس الأربعة الرئيسية هي الأسطر، الدوال، الفروع، والجمل، وتعتبر تغطية الفروع (Branch Coverage) ذات أهمية خاصة.
  • يمكننا بسهولة إنشاء تقرير تغطية باستخدام Vitest عبر الأمر npx vitest run --coverage.
  • يجب أن نستخدم تقارير التغطية كـ دليل إرشادي، مع تذكر أن الهدف الحقيقي هو كتابة اختبارات ذات جودة عالية، وليس مجرد الوصول إلى نسبة 100%.

في الدرس التالي، سنبدأ في استكشاف التقنيات الأساسية لكتابة اختبارات الوحدات بشكل احترافي.

قد تُعجبك هذه المشاركات

إرسال تعليق

ليست هناك تعليقات

7627059358572141466

العلامات المرجعية

قائمة العلامات المرجعية فارغة ... قم بإضافة مقالاتك الآن

    البحث