الاختبار القائم على الخصائص في Java: عندما يحل اختبار واحد محل ألف اختبار
\n\nهل سبق لك أن كتبت اختبار وحدة كان ناجحًا، وبعد أسبوع فشل في الإنتاج بسبب "قيمة غريبة ما"؟ هذا مألوف. الاختبار التقليدي (القائم على الأمثلة) يشبه التحقق من أن الغلاية تغلي فقط عند 100 درجة مئوية. ماذا لو كان الضغط مختلفًا؟ ماذا لو كان الارتفاع عن سطح البحر مختلفًا؟ يحل الاختبار القائم على الخصائص في Java هذه المشكلة بالضبط: بدلاً من المرور يدويًا على الأمثلة، تصف الخصائص التي يجب أن يفي بها الكود الخاص بك، ويقوم الإطار بتوليد مئات من بيانات الإدخال العشوائية والتحقق من أن كل شيء على ما يرام.
\n\nهذا النهج مفيد بشكل خاص لـ مطوري Java الذين يكتبون خوارزميات معقدة، أو يعملون مع المجموعات، أو المحللات اللغوية، أو الدوال الرياضية. في هذه المقالة، سنشرح كيفية دمج الاختبار القائم على الخصائص في مشروعك باستخدام مكتبة jqwik، وسنعرض أمثلة كود حقيقية.
\n\nما هو الاختبار القائم على الخصائص وكيف يختلف عن الاختبار التقليدي؟
\n\nفي النهج الكلاسيكي، تكتب:
\n\n@Test\nvoid testAddition() {\n assertEquals(4, Calculator.add(2, 2));\n assertEquals(0, Calculator.add(-1, 1));\n}\n\nكل شيء جيد، حتى يقوم شخص ما بتمرير Integer.MAX_VALUE. أو null. أو رقم سالب كبير جدًا. الاختبار القائم على الخصائص يقلب المنطق: أنت لا تقول "أتوقع هذه النتيجة"، بل تقول "لأي بيانات إدخال صحيحة، النتيجة تحقق الخاصية X".
على سبيل المثال، خاصية الجمع: add(a, b) == add(b, a) (التبديلية). أو add(a, 0) == a (العنصر المحايد). يقوم الإطار بتوليد آلاف الأزواج العشوائية a و b ويتحقق من عدم انتهاك الخاصية.
المزايا الرئيسية لـ الاختبار القائم على الخصائص:
\n- \n
- توليد تلقائي لبيانات الاختبار — تجد أخطاء لم تفكر فيها حتى. \n
- تقليل عدد الاختبارات — اختبار خاصية واحد يحل محل عشرات الاختبارات القائمة على الأمثلة. \n
- التحقق من الحالات الحدودية — تستطيع المولدات إنشاء قيم "خطيرة" (0، null، سلاسل فارغة، أعداد كبيرة). \n
- التصغير (Shrinking) — إذا فشل الاختبار، يقوم الإطار بتقليل بيانات الإدخال إلى أبسط مثال يمكن إعادة إنتاج الخطأ فيه. \n
مكتبات الاختبار القائم على الخصائص في Java
\n\nهناك عدة حلول ناضجة في السوق:
\n- \n
- jqwik — حديثة، خفيفة الوزن، تتكامل بشكل ممتاز مع JUnit 5. أوصي بها للبدء. \n
- QuickTheories — سريعة، ولكنها أقل شهرة. \n
- JUnit QuickCheck — فرع من أداة Scala القديمة، ولكن الدعم ضعيف. \n
سنستخدم jqwik، لأنه يحتوي على واجهة برمجة تطبيقات (API) الأكثر ملاءمة ووثائق ممتازة. أضف التبعية إلى pom.xml:
<dependency>\n <groupId>net.jqwik</groupId>\n <artifactId>jqwik</artifactId>\n <version>1.8.4</version>\n <scope>test</scope>\n</dependency>\n\nأو لـ Gradle:
\n\ntestImplementation 'net.jqwik:jqwik:1.8.4'\n\nكتابة أول اختبار قائم على الخصائص في Java
\n\nلنفترض أن لدينا دالة تعكس سلسلة نصية:
\n\npublic static String reverse(String s) {\n if (s == null) return null;\n return new StringBuilder(s).reverse().toString();\n}\n\nما الخاصية التي يمكن التحقق منها؟ إذا قمت بعكس السلسلة مرتين، ستحصل على السلسلة الأصلية. هذه خاصية مثالية لـ الاختبار القائم على الخصائص.
\n\nimport net.jqwik.api.*;\nimport static org.assertj.core.api.Assertions.assertThat;\n\nclass StringProperties {\n