اختبارات في Rust: unit, integration, e2e من الألف إلى الياء

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

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

ابدأ الدورة

مقدمة: لماذا الاختبارات في Rust ليست مجرد موضة، بل ضرورة

\n\n

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

\n\n

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

\n\n

1. اختبارات الوحدة: الأساس

\n\n

اختبارات الوحدة (unit tests) هي أسرع وأكثر مستوى اختبار عزلة. إنها تختبر دوالًا فردية، أو طرقًا، أو وحدات صغيرة بمعزل عن التبعيات الخارجية. في Rust، من المعتاد وضع اختبارات الوحدة في نفس الملف الذي يحتوي على الكود المختبر، داخل وحدة tests.

\n\n

1.1. الهيكل والسمات

\n\n

لإنشاء اختبار وحدة، يتم استخدام السمة #[test]. الدالة المميزة بها لا تأخذ وسائط ولا تُرجع شيئًا (أو تُرجع Result). إذا حدث ذعر (panic) داخل الدالة، يعتبر الاختبار فاشلاً.

\n\n
// src/lib.rs\npub 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        assert_eq!(add(2, 2), 4);\n    }\n\n    #[test]\n    fn test_add_negative() {\n        assert_eq!(add(-1, -1), -2);\n    }\n}
\n\n

لاحظ #[cfg(test)]. تضمن هذه السمة أن وحدة الاختبارات سيتم ترجمتها فقط عند تشغيل الاختبارات (cargo test). لن يتم تضمينها في بناء الإنتاج.

\n\n

1.2. وحدات الماكرو للتحقق

\n\n

توفر Rust العديد من وحدات الماكرو للتحقق من الادعاءات:

\n\n
    \n
  • assert!(expr) — تتحقق من أن التعبير صحيح.
  • \n
  • assert_eq!(left, right) — تتحقق من المساواة (تتطلب PartialEq و Debug).
  • \n
  • assert_ne!(left, right) — تتحقق من عدم المساواة.
  • \n
  • panic!("message") — تسبب ذعرًا إجباريًا (تُستخدم لاختبار الأخطاء).
  • \n
\n\n

1.3. اختبار الذعر باستخدام should_panic

\n\n

إذا كانت الدالة الخاصة بك يجب أن تسبب ذعرًا عند إدخال بيانات غير صحيحة، استخدم السمة #[should_panic]:

\n\n
pub fn divide(a: f64, b: f64) -> f64 {\n    if b == 0.0 {\n        panic!("Division by zero");\n    }\n    a / b\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    #[should_panic(expected = "Division by zero")]\n    fn test_divide_by_zero() {\n        divide(10.0, 0.0);\n    }\n}
\n\n

المعامل expected اختياري، لكنه يجعل الاختبار أكثر دقة: يجب أن يحتوي الذعر على السلسلة المحددة.

\n\n

2. اختبارات التكامل: التحقق من تفاعل الوحدات

\n\n

تتحقق اختبارات التكامل من كيفية عمل الأجزاء المختلفة من تطبيقك معًا. على عكس اختبارات الوحدة، فهي موجودة في دليل منفصل tests/ على مستوى جذر المشروع (بجانب src/). يتم ترجمة كل ملف في هذا المجلد كصندوق (crate) مكتبة منفصل.

\n\n

2.1. إنشاء اختبار تكامل

\n\n

أنشئ ملفًا tests/integration_test.rs:

\n\n
// tests/integration_test.rs\nuse my_crate::add; // نفترض أن الصندوق الخاص بك يسمى my_crate\n\n#[test]\nfn test_add_integration() {\n    let result = add(5, 10);\n    assert_eq!(result, 15);\n}
\n\n

لتشغيل اختبارات التكامل فقط

المدونات

توصيات الكتب