كفى تخمينًا: لماذا TDD ليس مازوخية بل قوة خارقة
\n\nتخيل: أنت تكتب كودًا. كل شيء يعمل. أنت راضٍ. بعد شهر تعود إلى المشروع، وتجري تغييرًا صغيرًا واحدًا - وكل شيء ينهار. مألوف؟ والآن تخيل أن لديك شبكة أمان تلتقط كل خطأ في ثانية. هذا هو TDD في TypeScript - التطوير من خلال الاختبارات.
\n\nيعتقد العديد من المطورين أن TDD مخصص للمثاليين أو لمشاريع NASA. مفاجأة: هذا ليس صحيحًا. التطوير الموجه بالاختبارات (Test Driven Development) هو أداة توفر ساعات من التصحيح، وترفع جودة الكود، وتجعل إعادة الهيكلة آمنة. في هذه المقالة، سنشرح TDD TypeScript بأمثلة حقيقية، بدون حشو أو تجريدات.
\n\nإذا كنت تكتب بلغة TypeScript وتريد التوقف عن الخوف من تعديلاتك الخاصة - تابع القراءة. سيكون ممتعًا.
\n\nما هو TDD (ولماذا لا يتعلق الأمر بـ "كتابة الاختبارات")
\n\nTDD (التطوير الموجه بالاختبارات) هو منهجية يتم فيها كتابة الاختبارات قبل الكود. يبدو جنونيًا؟ فقط للوهلة الأولى. تتكون دورة TDD من ثلاث خطوات:
\n\n- \n
- الأحمر (Red) - اكتب اختبارًا سيفشل بالتأكيد، لأن الكود غير موجود بعد. \n
- الأخضر (Green) - اكتب الحد الأدنى من الكود ليجتاز الاختبار. \n
- إعادة الهيكلة (Refactor) - حسّن الكود دون تغيير سلوكه. \n
وهكذا - في حلقة. كل جزء جديد من الوظائف يبدأ باختبار. هذا يضبط الانضباط، ويجبرك على التفكير في تصميم API مسبقًا، ويمنحك الثقة بأن كل شيء يعمل كالساعة.
\n\nبالمناسبة، اختبارات الوحدة TypeScript ليست مجرد "فحص للدوال". إنها توثيق، ومواصفات، وتأمين في زجاجة واحدة.
\n\nأدوات TDD في TypeScript: ما تحتاج لتثبيته
\n\nلـ اختبار TypeScript سنحتاج إلى:
\n\n- \n
- Jest - إطار الاختبار الأكثر شيوعًا. يعمل فورًا مع TypeScript. \n
- ts-jest - إعداد مسبق لـ Jest ليفهم TypeScript دون إعداد إضافي. \n
- @types/jest - أنواع للإكمال التلقائي في بيئة التطوير المتكاملة (IDE). \n
التثبيت بأمر واحد:
\n\nnpm install --save-dev jest ts-jest @types/jest typescript\n\nأضف إلى package.json سكريبت لتشغيل الاختبارات:
"scripts": {\n "test": "jest",\n "test:watch": "jest --watch"\n}\n\nالآن كل شيء جاهز لـ التطوير من خلال الاختبارات TypeScript.
\n\nنكتب أول اختبار وفقًا لـ TDD: من الأحمر إلى الأخضر
\n\nلنفترض أننا بحاجة لكتابة دالة تتحقق مما إذا كانت السلسلة النصية متناظرة (Palindrome). وفقًا للكلاسيكية في TDD - نبدأ بالاختبار.
\n\nالخطوة 1. الأحمر (Red)
\n\nننشئ ملف isPalindrome.test.ts:
import { isPalindrome } from './isPalindrome';\n\ndescribe('isPalindrome', () => {\n it('يجب أن يعيد true للسلسلة "racecar"', () => {\n expect(isPalindrome('racecar')).toBe(true);\n });\n\n it('يجب أن يعيد false للسلسلة "hello"', () => {\n expect(isPalindrome('hello')).toBe(false);\n });\n});\n\nنشغل الاختبار:
\n\nnpm test\n\nنرى خطأ: Cannot find module './isPalindrome'. ممتاز، تم اجتياز المرحلة الحمراء. الآن نحتاج لكتابة كود ليجتاز الاختبار.
الخطوة 2. الأخضر (Green)
\n\nننشئ isPalindrome.ts بأقل تنفيذ:
export function isPalindrome(str: string): boolean {\n return str === str.split('').reverse().join('');\n}\n\nنشغل الاختبارات مرة أخرى - أخضر! كلا الاختبارين ينجحان. لكن هذا ليس كل شيء.
\n\nالخطوة 3. إعادة الهيكلة (Refactor)
\n\nالدالة تعمل، لكن هناك فارق بسيط: لا تعالج السلاسل التي تحتوي على مسافات وأحرف مختلفة. سنضيف اختبارًا جديدًا:
\n\nit('يجب أن يتجاهل حالة الأحرف والمسافات',