لماذا TDD ليس عن "كتابة اختبارات"، بل عن "التفكير بطريقة مختلفة"
\n\nتخيل أنك تبني منزلًا. لديك المخططات والمواد وطاقم العمل. لكنك تبدأ في وضع الطوب دون التحقق من الأساس. بعد شهر، تكتشف أن الجدران بدأت تتشقق. هل يبدو الأمر مألوفًا؟ في البرمجة، يُسمى هذا "سنصلحه لاحقًا". وعادةً ما يأتي "لاحقًا" في الساعة الثالثة صباحًا قبل النشر.
\n\nالتطوير القائم على الاختبارات (TDD — Test-Driven Development) هو أسلوب يقلب العملية رأسًا على عقب. أنت لا تكتب الكود ثم الاختبارات. أنت تكتب الاختبار أولاً — وبعدها فقط الكود الذي يجتاز هذا الاختبار. هل يبدو هذا جنونيًا؟ عمليًا، هذا يوفر ساعات وأعصابًا ويجعل الكود أنقى من هواء الجبال في الصباح.
\n\nفي هذه المقالة، سنشرح TDD في Java من خلال أمثلة محددة. لا ماء — فقط كود، دورة Red-Green-Refactor، وسيناريوهات حقيقية. هيا بنا.
\n\nما هو TDD وكيف تعمل دورة Red-Green-Refactor
\n\nيعتمد TDD على ثلاث خطوات بسيطة تتكرر بشكل دوري:
\n\n- \n
- Red — نكتب اختبارًا لا يجتاز (يجب أن يفشل). \n
- Green — نكتب الحد الأدنى من الكود ليجتاز الاختبار. \n
- Refactor — نحسن الكود دون تغيير سلوكه. تظل الاختبارات خضراء. \n
قد يبدو أن هذا يبطئ التطوير. في الواقع — إنه يسرعه. تتوقف عن التخمين "هل هذا يعمل؟". أنت تعلم: إنه يعمل، لأن الاختبار أخضر.
\n\nالمبادئ الرئيسية لـ TDD
\n- \n
- لا تكتب سطرًا واحدًا من كود الإنتاج بدون اختبار. \n
- يجب أن يكون الاختبار بسيطًا قدر الإمكان وأن يختبر سلوكًا واحدًا فقط. \n
- يُكتب الكود بالقدر الذي يجعله يجتاز الاختبار فقط. لا "دعنا نضيف هذا أيضًا تحسبًا". \n
الآن دعنا ننتقل إلى Java و JUnit 5 — الإطار الأكثر شيوعًا لاختبارات الوحدة.
\n\nإعداد المشروع: Maven, JUnit 5 والهيكل
\n\nلأمثلتنا، سنستخدم Maven. أضف التبعية إلى pom.xml:
<dependency>\n <groupId>org.junit.jupiter</groupId>\n <artifactId>junit-jupiter-api</artifactId>\n <version>5.10.0</version>\n <scope>test</scope>\n</dependency>\n\nهيكل المجلدات قياسي لـ Maven:
\nsrc/\n main/java/com/example/\n test/java/com/example/\n\nنضع جميع فئات الاختبار في src/test/java. عادةً ما يتطابق اسم فئة الاختبار مع اسم الفئة المختبرة + اللاحقة Test. على سبيل المثال، Calculator → CalculatorTest.
دورة TDD الأولى: كتابة آلة حاسبة من الصفر
\n\nالمهمة: إنشاء دالة add(int a, int b) تُرجع المجموع. وفقًا لـ TDD، نبدأ ليس بالفئة، بل بالاختبار.
الخطوة 1: Red — نكتب اختبارًا سيفشل
\n\nimport org.junit.jupiter.api.Test;\nimport static org.junit.jupiter.api.Assertions.*;\n\npublic class CalculatorTest {\n\n @Test\n void shouldAddTwoNumbers() {\n Calculator calc = new Calculator();\n int result = calc.add(2, 3);\n assertEquals(5, result);\n }\n}\n\nنحاول التشغيل — المترجم يشتكي: الفئة Calculator غير موجودة. ممتاز، الضوء الأحمر مضاء.
الخطوة 2: Green — نكتب الحد الأدنى من الكود
\n\nننشئ فئة Calculator بدالة تُرجع المجموع ببساطة:
public class Calculator {\n public int add(int a, int b) {\n return a + b;\n }\n}\n\nنشغل الاختبار — أخضر. التطبيق الأدنى الممكن نجح.
\n\nالخطوة 3: Refactor
\n\nفي هذه المرحلة، الكود بسيط بالفعل، لا شيء لإعادة هيكلته. لكن لنفترض أننا نريد إعادة تسمية الدالة أو إضافة فحص للفيضان. نفعل ذلك، ولا يزال الاختبار ناجحًا. إذا حدث خطأ ما — سيفشل الاختبار ويشير فورًا إلى المشكلة.
\n\n