اختبار التحور في Kotlin: كيفية كتابة كود لا يخاف من التغيير

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

لماذا تغطية الكود (code coverage) هي فخ، واختبار التحور (mutation testing) هو الخلاص

\n\n

تخيل موقفًا: مشروعك بلغة Kotlin مغطى بالاختبارات بنسبة 95%. CI أخضر، المدير سعيد، الكود يذهب إلى الإنتاج. وبعد أسبوع - خطأ في الإنتاج. هل هذا مألوف؟ على الأرجح، اختباراتك ببساطة تُنفَّذ، لكنها لا تتحقق من المنطق. هنا يأتي دور اختبار التحور (mutation testing) - منهجية لا تسمح للاختبارات بـ"التساهل".

\n\n

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

\n\n

ما هو اختبار التحور؟ أشرحه باستخدام القطط

\n\n

لنفترض أنك كتبت دالة تحدد ما إذا كان بإمكان القط المرور عبر الباب:

\n\n
fun canCatFitThroughDoor(catWidth: Int, doorWidth: Int): Boolean {\n    return catWidth <= doorWidth\n}
\n\n

كتبت اختبارًا:

\n\n
@Test\nfun `قط بعرض 30 يمر عبر باب بعرض 40`() {\n    assertTrue(canCatFitThroughDoor(30, 40))\n}
\n\n

التغطية - 100%. ولكن ماذا لو قام شخص ما بتغيير <= إلى < عن طريق الخطأ؟ سيظل الاختبار ناجحًا! يقوم اختبار التحور تلقائيًا بإدخال مثل هذه "الأعطال الصغيرة" (التحورات) في الكود ويتحقق مما إذا كان اختبار واحد على الأقل سيفشل. إذا لم يفشل الاختبار - فإن اختباراتك لا تكتشف هذا الخطأ. هذا هو اختبار التحور في Kotlin.

\n\n

كيف يعمل اختبار التحور: من العوامل إلى "الطفرات الناجية"

\n\n

تقوم الأداة (مثل Pitest لـ Kotlin) بإنشاء طفرات - إصدارات من كودك مع تغيير واحد. إليك التحورات النموذجية:

\n\n
    \n
  • تغيير عوامل المقارنة: > → >=, == → !=
  • \n
  • عكس الشروط: if (a > b) → if (a <= b)
  • \n
  • إزالة استدعاءات الدوال: someMethod() → فارغ
  • \n
  • استبدال القيم المُرجعة: true → false
  • \n
  • تغيير الأرقام: 10 → 11 أو 0
  • \n
\n\n

بعد إنشاء الطفرات، يتم تشغيل جميع اختباراتك. تنقسم النتائج إلى ثلاث فئات:

\n\n
    \n
  • الطفرات المقتولة (Killed) - فشلت الاختبارات، تم اكتشاف التحور. ممتاز!
  • \n
  • الطفرات الناجية (Survived) - نجحت الاختبارات على الرغم من تغيير الكود. إشارة تحذيرية.
  • \n
  • مغطاة ولكن غير مقتولة (Covered but not killed) - تم تشغيل الاختبارات ولكنها لم تلاحظ التغيير.
  • \n
\n\n

هدفك هو تقليل عدد الطفرات الناجية قدر الإمكان (من الناحية المثالية - 0). هذا هو اختبار التحور لكود Kotlin عمليًا.

\n\n

Pitest: الأداة الرئيسية لـ Kotlin

\n\n

بالنسبة للغات JVM (Java, Kotlin)، المعيار الفعلي هو Pitest (PIT Mutation Testing). وهو يدعم Kotlin من خلال الإضافة pitest-kotlin. إليك كيفية توصيله في Gradle:

\n\n
plugins {\n    id("info.solidsoft.pitest") version "1.15.0"\n}\n\npitest {\n    targetClasses.set(listOf("com.myapp.*")) // الفئات التي سيتم تحويرها\n    targetTests.set(listOf("com.myapp.*"))    // الاختبارات التي سيتم تشغيلها\n    threads.set(4)                            // خيوط متوازية\n    outputFormats.set(listOf("XML", "HTML"))  // التقارير\n    mutationThreshold.set(80)                 // الحد الأدنى لنسبة المقتولة\n    timeoutConstInMillis.set(10000)           // مهلة الاختبار\n}\n\ndependencies {\n    testImplementation("org.pitest:pitest-kotlin:1.15.0")\n}
\n\n

التشغيل بأمر واحد:

\n\n
./gradlew pitest
\n\n

بعد التنفيذ، في build/reports/pites

المدونات

توصيات الكتب