ConstructiCat Logo
CodeBust.
Browse section ▾

الاختبار الفارغ.

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

##Signs and Symptoms

يوجد اختبار ويتم الإبلاغ عنه على أنه ناجح، ولكن جسمه لا يحتوي على كود قابل للتنفيذ — لا تهيئة، ولا تشغيل، ولا تحقق. الأشكال الدالة:

// جسم فارغ تماماً
test('calculates tax', () => {});

// تعليق TODO / تعليق عنصر نائب فقط
it('should reject invalid input', () => {
  // TODO: اكتب هذا بمجرد استقرار واجهة برمجة التطبيقات (API)
});

// تم تحويل كل شيء إلى تعليق
it('parses the auth header', () => {
  // const result = parse(header);
  // expect(result).toEqual(expected);
});

كيف تكتشفه:

  • يعد اسم الاختبار بسلوك معين، ولكن جسم الاختبار يحتوي على {} أو مسافات فارغة أو تعليقات فقط.
  • يظهر ملخص بيئة التشغيل الاختبار كـ ناجح (أخضر)، وليس كمتخطى/معلق — وهذا هو ما يجعله خطيراً.
  • تكون تغطية الكود للميزة المسماة صفراً بشكل مريب على الرغم من وجود "اختبار لها".
  • أثناء المراجعة، يضيف الفارق (diff) حالة اختبار ولكن بدون استدعاء expect/assert call.

مرتبط ولكنه متميز: الاختبار الذي يحتوي على تهيئة ويستدعي النظام تحت الاختبار ولكنه لا يجري أي تحقق يمثل رائحة الاختبار الخالي من التحقق / الاختبار المجهول. بينما الاختبار الفارغ هو الحالة الأكثر تطرفاً حيث يكون جسم الاختبار خالياً تماماً من أي عبارات.

##Reasons for the Problem

لماذا يحدث ذلك

  • تم إنشاء هيكل الاختبار كعنصر نائب (مثل أسلوب TDD "اكتب الاسم أولاً") ولم يتم ملؤه أبداً.
  • تم تحويل الكود إلى تعليق لتصحيح خطأ أو لإسكات اختبار غير مستقر، ثم تم رفعه ونسيانه.
  • أنتج مولد الأكواد أو محرّر الأكواد (IDE) اختباراً هيكلياً فارغاً لم يكمله أحد.
  • أراد المطور "حجز" اسم اختبار لوقت لاحق ولكنه استخدم جسماً فارغاً بدلاً من علامة todo صريحة.

لماذا يضر ذلك

  • الثقة الزائفة (الجزء الأسوأ). تبلغ معظم بيئات تشغيل الاختبارات عن نجاح الاختبار الفارغ كـ ناجح، وليس كمتخطى. ستظهر جميع بيئات التشغيل مثل JUnit وJest وVitest وغيرها لوناً أخضر لـ test('x', () => {}). تبدو مجموعة الاختبارات وكأنها تغطي السلوك، ولكن لن يتم التقاط أي تراجع في كود الإنتاج أبداً — وهو أمر ربما يكون أسوأ من عدم وجود اختبار على الإطلاق، لأن علامة النجاح الخضراء تضلل بشكل نشط.
  • سهولة القراءة. يرى القارئ اختباراً باسم should reject invalid input ويفترض منطقياً أن هذا السلوك قد تم التحقق منه. يوثق الاسم نية لا يقدمها جسم الاختبار أبداً.
  • سهولة الصيانة. تضخم الاختبارات الفارغة عدد الاختبارات وتصور التغطية بالاسم، مما يخفي الفجوات الحقيقية ويجعل من الصعب التمييز بين العناصر النائبة المقصودة وتلك المهجورة.
  • يضعف الثقة. بمجرد أن يدرك المساهمون في الكود أن "النجاح" لا يعني "التحقق من الصحة"، تضعف مصداقية مجموعة الاختبارات بأكملها.

##Treatment

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

1. إذا كان يجب اختبار السلوك الآن — املأ جسم الاختبار. أضف خطوات الترتيب والتنفيذ والتحقق (arrange/act/assert) بحيث يختبر الكود فعلياً:

// قبل — ناجح (أخضر)، ولكنه لا يتحقق من شيء
test('rounds half up', () => {});

// بعد — توقع حقيقي
test('rounds half up', () => {
  expect(round(2.5)).toBe(3);
});

2. إذا كان عنصراً نائباً حقيقياً — ضع عليه علامة معلق صريحة بحيث تبلغ بيئة التشغيل عنه كـ todo/skipped (مرئي، وليس أخضر كاذباً) بدلاً من ترك جسمه فارغاً:

// قبل
it('should reject invalid input', () => {
  // TODO
});

// بعد — يظهر كـ todo في التقرير، ولا يظهر أبداً كـ "ناجح"
it.todo('should reject invalid input');   // Jest / Vitest
// أو test.skip(...) / xit(...) مع تذكرة تتبع

3. إذا كان الاختبار قديماً وغير مستخدم — فاحذفه. الاختبار المحذوف يعبر عن الحقيقة؛ بينما الاختبار الفارغ كذبة تكلف صيانة.

4. استعد المنطق المعلق. إذا كان جسم الاختبار معلقاً بالكامل، فإما أن تلغي التعليق وتصلحه أو تزيل الاختبار؛ ولا تشحن أبداً كود اختبار معلقاً كـ "تنفيذ".

5. أضف حماية. فعّل قاعدة فحص وجود التحقق (assertion-presence lint rule) (انظر كواشف الرائحة) في التكامل المستمر (CI) بحيث تفشل الاختبارات الفارغة/الخالية من التحقق في البناء بدلاً من النجاح بصمت.

##Detected by

  • eslint-jest expect-expecteslint-plugin-jest: expect-expect (يحدد الاختبارات التي لا تحتوي على تحقق، بما في ذلك الأجسام الفارغة)
  • eslint-vitest expect-expecteslint-plugin-vitest: expect-expect (يفرض وجود توقع واحد على الأقل لكل اختبار)
  • eslint no-empty-functionESLint core: no-empty-function (قاعدة عامة؛ تحدد جسم الدالة السهمية/الدالة الفارغة في استدعاء اختبار فارغ)
  • sonar S2699SonarSource: S2699 "يجب أن تحتوي الاختبارات على تحققات" (حظر؛ يحدد الاختبارات الخالية من التحقق والاختبارات الفارغة؛ وتوجد مكافئات لـ Java/C#/Python)
  • pmd JUnitTestsShouldIncludeAssertPMD (Java): JUnitTestsShouldIncludeAssert (يحدد اختبارات JUnit التي تفتقر إلى تحقق، بما في ذلك الاختبارات الفارغة)