تغطية الكود (Code Coverage) هي مقياس يوضح النسبة المئوية للكود المصدري للتطبيق التي يتم تنفيذها أثناء الاختبار. تساعد في تحديد جودة الاختبارات، اكتشاف الأجزاء غير المختبرة، وتحديد أولويات كتابة اختبارات جديدة. وفقًا لـ Atlassian، 2025، فإن المستوى الأمثل للتغطية هو 70–80% — فوق هذه العتبة، تبدأ تكاليف الاختبار في تجاوز الفوائد.
الخلاصة
تغطية الكود (Code Coverage) هي مقياس كمي يحدد أي جزء من الكود المصدري للتطبيق تم تنفيذه أثناء الاختبارات. يتم التعبير عنها كنسبة مئوية وتحسب كنسبة السطور/الفروع المنفذة إلى الإجمالي. التغطية العالية لا تضمن عدم وجود أخطاء، ولكنها تقلل من خطر الأخطاء غير المكتشفة.
تساعد تغطية الكود الفريق في: اكتشاف الأجزاء غير المختبرة من الكود، اتخاذ القرارات حول أولويات كتابة الاختبارات، تتبع ديناميكيات جودة الاختبار في CI/CD. في تطوير التطبيقات المحمولة، التغطية مهمة بشكل خاص لمنطق الأعمال، نماذج البيانات والمستودعات — الطبقات التي يكون فيها احتمال الأخطاء أعلى.
خرافة شائعة: «تغطية 100% = جودة مثالية». في الممارسة العملية، تغطية 100% نادرة للغاية وغالبًا ما تكون على حساب اختبارات سطحية. التغطية الفعالة ليست سباقًا نحو النسبة المئوية، بل تغطية استراتيجية للمسارات الحرجة والحالات الحدودية. التغطية لا تخبرنا شيئًا عن جودة الاختبارات نفسها: قد ينجح الاختبار لكنه لا يتحقق من صحة النتيجة.
توجد عدة مقاييس لتغطية الكود، كل منها يقيس جوانب مختلفة من الاختبار. تغطية السطور (Line coverage) هي أبسط مقياس، يوضح النسبة المئوية لسطور الكود المنفذة. تغطية الفروع (Branch coverage) تقيس أي تقسيمات if-else و switch تم اختبارها.
تغطية السطور تحسب كل سطر من الكود المصدري كمنفذ أو غير منفذ. إذا كان السطر يحتوي على عامل شرطي أو حلقة، يعتبر السطر منفذًا إذا وصل التحكم إليه، حتى لو لم تتم معالجة جميع الفروع. هذا هو المقياس الأقل صرامة، لكنه الأكثر فهماً للتقييم البصري.
تغطية الفروع تقيم ما إذا كانت جميع التفرعات الممكنة في الكود قد تم اختبارها. لكل if-else يتم أخذ كلا الفرعين في الاعتبار: true و false. بالنسبة لـ switch، يتم أخذ كل case. تغطية الفروع تعتبر مقياسًا أكثر صرامة من تغطية السطور وتكشف غالبًا عن سيناريوهات غير مختبرة.
| المقياس | ما يقيسه | صعوبة التحقيق |
|---|---|---|
| Line | نسبة سطور الكود المنفذة | منخفضة |
| Branch | نسبة الفروع المنفذة (if/else, switch) | متوسطة |
| Function | نسبة الدوال والطرق المستدعاة | منخفضة |
| Condition | نسبة التعبيرات الفرعية المنطقية (&&, ||) | عالية |
تغطية المسارات هي المقياس الأكثر صرامة، وتتطلب التحقق من جميع التوليفات الممكنة للتفرعات في الدالة. في الممارسة العملية، نادرًا ما تستخدم تغطية المسارات بسبب النمو الأسي لعدد التوليفات: دالة بها 10 تفرعات لديها 1024 مسارًا ممكنًا.
في تطوير التطبيقات المحمولة، تُستخدم أدوات مختلفة لقياس تغطية الكود حسب المنصة. لنظام Android، المعيار هو JaCoCo (Java Code Coverage)، الذي يتكامل مع Gradle ويدعم كلاً من اختبارات الوحدة واختبارات الأجهزة. لنظام iOS، يُستخدم XCCov المدمج في Xcode.
JaCoCo ينشئ تقارير بتنسيقات HTML و XML و CSV. تقرير HTML يبرز السطور بصريًا: أخضر — منفذة، أحمر — مفقودة، أصفر — منفذة جزئيًا. تقرير XML متوافق مع SonarQube وأنظمة تحليل الكود الأخرى. JaCoCo يدعم تصفية الفئات: يمكن استبعاد الكود المُنشأ، ربط البيانات و BuildConfig.
// build.gradle — إعداد JaCoCo
android {
buildTypes {
debug {
testCoverageEnabled = true
}
}
}
// إنشاء تقرير JaCoCo
task jacocoTestReport(type: JacocoReport) {
dependsOn 'testDebugUnitTest'
reports {
xml.enabled = true
html.enabled = true
}
}
XCCov هي أداة مدمجة في Xcode لقياس تغطية الكود. يتم تفعيلها عبر Gather coverage data في مخطط الاختبار. XCCov يدعم التغطية لـ Swift و Objective-C، وينشئ تقارير بتنسيق .xccovreport ويتكامل مع CI عبر xcodebuild -enableCodeCoverage YES. يتم إخراج البيانات إلى وحدة التحكم ويمكن تصديرها بتنسيق JSON.
للمراقبة المركزية للتغطية، تُستخدم منصات مثل SonarQube (تحليل جودة الكود + تغطية)، Codecov و Coveralls. هذه الخدمات تجمع البيانات من JaCoCo و XCCov، وتعرض الاتجاهات، وبوابة الجودة (Quality Gate)، والتكامل مع GitHub/GitLab عبر تعليقات PR.
تحسين تغطية الكود يتطلب نهجًا منهجيًا: ليس «رفع النسب المئوية»، بل تغطية المخاطر. الخطوة الأولى هي تحليل تقرير JaCoCo أو XCCov — تحديد الفئات الحمراء (غير المغطاة). الأولوية: منطق الأعمال → المستودعات → ViewModel → مكونات واجهة المستخدم.
التطوير القائم على الاختبار (TDD) يضمن تلقائيًا تغطية عالية، لأن الاختبارات تُكتب قبل التنفيذ. العملية: أحمر (كتابة اختبار فاشل) → أخضر (كتابة الحد الأدنى من الكود) → إعادة هيكلة. TDD يُنظم المطور، مما يجبره على تغطية الحالات الحدودية والمواقف الاستثنائية التي غالبًا ما تبقى بدون اختبارات.
اختبار واحد مُعلم يحل محل عشرات الاختبارات العادية. JUnit و XCTest يدعمان التوسيم: @ParameterizedTest في JUnit 5، XCTestCase مع testPerformanceExample في XCTest. التوسيم يسمح بفحص العديد من بيانات الإدخال دون تكرار الكود، مما يوسع بشكل كبير تغطية الفروع والشروط.
// اختبار مُعلم في Kotlin مع JUnit 5
@ParameterizedTest
@ValueSource(strings = ["user@test.com", "admin@test.com", "test@example.com"])
fun `validate email returns true for valid addresses`(email: String) {
val result = EmailValidator.isValid(email)
Assertions.assertTrue(result)
}
الخطأ الأكثر شيوعًا هو السعي وراء النسبة المئوية دون تحليل جودة الاختبارات. يبدأ الفريق في كتابة اختبارات من أجل الاختبارات: التحقق من getters و setters، تكرار التغطية على مستويات مختلفة، اختبار طرق تافهة. هذا يعطي نسبة مئوية عالية لكنه لا يحسن الجودة الحقيقية.
تغطية عالية للكود يمكن أن تخلق شعورًا زائفًا بأن التطبيق مختبر جيدًا. قد ينفذ الاختبار سطرًا من الكود لكنه لا يتحقق من صحة النتيجة. على سبيل المثال: اختبار يستدعي طريقة حساب الخصم لكنه لا يتحقق من المبلغ — السطر منفذ، التغطية تزيد، لكن الخطأ لا يُكتشف.
خطأ نموذجي هو اختبار «المسار السعيد» (happy path) فقط وتجاهل الحالات الحدودية: القوائم الفارغة، قيم null، الأرقام القصوى، التنسيقات غير الصحيحة. على الحدود والاستثناءات تحدث معظم الأخطاء. تغطية الفروع تساعد في اكتشاف الفروع المفقودة، لكنها لا تضمن التحقق من القيم الحدودية.
اختبار التحول (Mutation Testing) هو طريقة لتقييم جودة الاختبارات حيث يتم إدخال تحولات (أخطاء اصطناعية) في الكود المصدري والتحقق مما إذا كانت الاختبارات تفشل. Pitest هي أداة شائعة لاختبار التحول في Java و Kotlin. إذا لم تفشل الاختبارات عند التحول، فهذا يعني أنها لا تتحقق من هذا الشرط.
Pitest ينشئ متحولين — نسخًا معدلة من الكود المصدري حيث، على سبيل المثال، يتم استبدال > بـ >=، true بـ false، أو إزالة استدعاء طريقة. ثم لكل متحول يتم تشغيل الاختبارات. إذا نجحت الاختبارات — نجا المتحول، مما يعني أن الاختبارات لا تغطي هذا السيناريو. إذا فشلت الاختبارات — تم قتل المتحول، الاختبار صحيح.
// build.gradle — إعداد Pitest
plugins {
id 'info.solidsoft.pitest' version '1.15.0'
}
pitest {
targetClasses = ['com.example.app.*']
targetTests = ['com.example.app.*Test']
threads = 4
outputFormats = ['HTML', 'XML']
mutationThreshold = 80
coverageThreshold = 85
}
Pitest يدعم العديد من أنواع التحولات: تغيير العوامل الشرطية (== → !=, < → <=)، إزالة استدعاءات الطرق، استبدال قيم الإرجاع (true → false)، تغيير العمليات الحسابية (+ → -)، تحول الزيادات (i++ → i--). كلما زادت أنواع التحولات التي تقتلها الاختبارات، كانت مجموعة الاختبارات أكثر موثوقية.
درجة التحول المستهدفة هي 80% أو أعلى. هذا يعني أن 80% من الأخطاء الاصطناعية يتم اكتشافها بواسطة الاختبارات. تغطية الكود بنسبة 90% لا تضمن أن الاختبارات تجد الأخطاء — اختبار التحول يوفر تقييمًا أكثر موضوعية. Pitest يمكن دمجه في CI كبوابة جودة، مما يمنع البناء عند انخفاض درجة التحول تحت العتبة.
للتحكم التلقائي في تغطية الكود في CI/CD، تُستخدم بوابات الجودة (Quality Gates) — قيم عتبة، عند انتهاكها، يتم وضع علامة على البناء كغير مستقر أو رفضه. SonarQube يسمح بتكوين بوابة الجودة بناءً على مجموعة من المقاييس: التغطية (≥80%)، عدد الأخطاء، الثغرات الأمنية والكود المكرر.
في GitHub Actions، يتم دمج تغطية الكود من خلال خطوات الإجراء: تشغيل الاختبارات مع التغطية → تحميل التقرير إلى Codecov → التحقق من العتبة. Codecov يعلق تلقائيًا على PR مع فرق التغطية، موضحًا أي السطور تغيرت وكيف أثر ذلك على النسبة المئوية الإجمالية. إذا انخفضت التغطية، يتم حظر PR حتى كتابة اختبارات إضافية.
# GitHub Actions — تحميل التغطية إلى Codecov
- name: Run Tests with Coverage
run: ./gradlew testDebugUnitTest jacocoTestReport
- name: Upload to Codecov
uses: codecov/codecov-action@v4
with:
files: ./app/build/reports/jacoco/jacocoTestReport.xml
flags: unittests
fail_ci_if_error: true
- name: Check Coverage Threshold
run: |
coverage=$(grep -oP 'branchCoverage="\K[0-9.]+' report.xml)
if (( $(echo "$coverage < 80" | bc -l) )); then
echo "Coverage $coverage% is below 80% threshold"
exit 1
fi
تقارير HTML من JaCoCo و XCCov تحتوي على تمييز بصري للتغطية: أخضر — سطور منفذة، أحمر — غير منفذة. SonarQube بالإضافة إلى ذلك يُظهر التغطية على مستوى الملف، الفئة، الطريقة والسطر، بالإضافة إلى تاريخ تغيير التغطية عبر السباقات. هذا يساعد في اتخاذ قرارات حول إعادة الهيكلة وإضافة الاختبارات.
الأسئلة الشائعة
للمشاريع المحمولة، تعتبر التغطية 70–80% لمنطق الأعمال و 50–60% لمكونات واجهة المستخدم جيدة. فوق 80%، تبدأ تكاليف الاختبار في تجاوز الفوائد. من المهم تذكر أن النسبة المئوية ليست هدفًا بل مؤشر، وقد يكون للوحدات المختلفة مستويات مستهدفة مختلفة.
تغطية السطور توضح عدد سطور الكود التي تم تنفيذها. تغطية الفروع توضح عدد التفرعات (if-else, switch) التي تم اختبارها. قد يتم تنفيذ سطر يحتوي على if، ولكن قد يتم اختبار الفرع true فقط وليس false. تغطية الفروع أكثر صرامة وتكشف المزيد من السيناريوهات المفقودة.
في CI/CD، يتم دمج التغطية عبر بوابة الجودة (Quality Gate): يتم حظر البناء إذا كانت التغطية أقل من العتبة. لنظام Android، يُستخدم JaCoCo + SonarQube، لنظام iOS — xcodebuild -enableCodeCoverage مع تحليل .xccovreport. GitHub Actions يحتوي على إجراءات جاهزة لـ Codecov.
نعم، JaCoCo يدعم Jetpack Compose عبر آلية تغطية JVM القياسية. ومع ذلك، يحتوي كود Compose على العديد من تعبيرات lambda المُنشأة التي قد لا يغطيها JaCoCo بالكامل. يُوصى باستبعاد كود Compose المُنشأ من التقرير عبر المرشحات.
تحدث التغطية الزائفة عندما ينفذ الاختبار كودًا لكنه لا يتحقق من النتيجة. الحل: كتابة تأكيدات (assert) لكل سيناريو مهم، استخدام اختبار التحول (Pitest) للتحقق من جودة الاختبارات، تحليل ليس فقط النسبة المئوية ولكن أيضًا أي الفروع مغطاة.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.