TDD في Rust: تطوير يعتمد على الاختبارات لكتابة كود موثوق

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

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

ابدأ الدورة

لماذا TDD في Rust ليس مملًا، بل مفيدًا؟

\n\n

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

\n\n

Rust هي لغة تحميك بالفعل على مستوى المترجم من فئة كاملة من الأخطاء (وداعًا لـ segfaults وسباقات البيانات!). ولكن حتى المترجم لا يضمن صحة منطقك. يضيف TDD في Rust طبقة أخرى إلى هذه الأمان: أنت لا تكتب الكود فحسب، بل توثق السلوك المتوقع مباشرة في الاختبارات. وهذا أمر رائع بشكل لا يصدق.

\n\n

في هذه المقالة، سنشرح TDD في Rust بأمثلة حية. سترى كيف تكتب الاختبارات قبل التنفيذ، وكيف تشغلها باستخدام cargo test، وكيف تعيد هيكلة الكود دون خوف من كسر شيء ما. هيا بنا!

\n\n

ما هو TDD ولماذا Rust مثالي له؟

\n\n

TDD تعني Test-Driven Development (التطوير القائم على الاختبارات). الدورة بسيطة وأنيقة:

\n\n
    \n
  1. الأحمر — نكتب اختبارًا يصف وظيفة جديدة. نشغله — يفشل الاختبار (منطقي، لا يوجد كود بعد).
  2. \n
  3. الأخضر — نكتب الحد الأدنى من الكود ليجتاز الاختبار. لا نفكر في الجمال، فقط في اجتياز الاختبار.
  4. \n
  5. إعادة الهيكلة — نحسن الكود دون تغيير سلوكه. تظل الاختبارات خضراء.
  6. \n
\n\n

Rust مثالي لـ TDD لعدة أسباب:

\n
    \n
  • نظام اختبار مدمج — cargo test يعمل فورًا، لا حاجة لتثبيت أطر خارجية.
  • \n
  • الكتابة الصارمة للأنواع — يكتشف المترجم أخطاء الأنواع، وتكتشف الاختبارات الأخطاء المنطقية. معًا لا يُقهرون.
  • \n
  • الملكية والاقتراض — تساعد الاختبارات في التأكد من أنك تتعامل مع الذاكرة بشكل صحيح، دون إنشاء نسخ غير ضرورية.
  • \n
  • المجتمع والتوثيق — مجتمع Rust يروج بنشاط للاختبارات، والأمثلة وفيرة.
  • \n
\n\n

إعداد المشروع لـ TDD

\n\n

لننشئ مشروعًا جديدًا:

\n
cargo new tdd_rust_example\ncd tdd_rust_example
\n\n

افتراضيًا، يقوم cargo new بإنشاء ملف src/main.rs مع برنامج بسيط. سنكتب مكتبة، لذا سنعيد تسميته إلى src/lib.rs (أو ببساطة نحذف main.rs وننشئ lib.rs). في Cargo.toml لا حاجة لتغيير شيء — الاختبارات مضمنة بالفعل.

\n\n

بالمناسبة، إذا كنت تكتب مكتبة فقط (بدون ملف تنفيذي)، استخدم cargo new --lib.

\n\n

الاختبار الأول: الأحمر

\n\n

تخيل أننا نريد كتابة دالة تجمع رقمين. وفقًا لـ TDD، نكتب الاختبار أولاً. افتح src/lib.rs وأضف:

\n\n
#[cfg(test)]\nmod tests {\n    #[test]\n    fn test_add() {\n        let result = add(2, 3);\n        assert_eq!(result, 5);\n    }\n}
\n\n

نشغل:

\n
cargo test
\n\n

سترى خطأ في الترجمة — الدالة add غير معرفة. هذا طبيعي. نحن في المنطقة الحمراء.

\n\n

الأخضر: الحد الأدنى من التنفيذ

\n\n

الآن نكتب القدر الكافي من الكود ليجتاز الاختبار. أضف الدالة add فوق وحدة الاختبارات:

\n\n
fn add(a: i32, b: i32) -> i32 {\n    a + b\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    \n    #[test]\n    fn test_add() {\n        let result = add(2, 3);\n        assert_eq!(result, 5);\n    }\n}
\n\n

لاحظ use super::*; — هذا يستورد كل شيء من الوحدة الأم (الكود الخاص بنا) إلى وحدة الاختبارات.

\n\n

نشغل cargo test مرة أخرى. أخضر! اجتاز الاختبار. لقد فعلنا الحد الأدنى — أعدنا المجموع. يبدو

المدونات

توصيات الكتب