proptest لـ Rust: دليل شامل لاختبار الخصائص (Property-Based Testing)
1. ما هي مكتبة proptest ولماذا تحتاجها؟
مكتبة proptest هي إطار عمل قوي لـ اختبار الخصائص (property-based testing) في لغة Rust. على عكس الاختبارات التقليدية (unit testing) حيث تحدد يدويًا بيانات الإدخال والنتيجة المتوقعة، يطلب منك اختبار الخصائص وصف خصائص (ثوابت) يجب أن تتحقق لـ أي بيانات إدخال صحيحة. بعد ذلك، تقوم المكتبة تلقائيًا بتوليد العديد من حالات الاختبار العشوائية والتحقق من عدم انتهاك الخاصية المحددة.
لماذا تحتاج هذا؟ أولاً، يساعدك في اكتشاف الحالات الحدية (edge cases) التي قد لا تخطر ببال المطور: سلاسل فارغة، أرقام سالبة، قيم كبيرة جدًا، حالات تشبه القيم الفارغة. ثانيًا، اختبارات الخصائص توثق نفسها بنفسها: فهي تصف عقد الدالة ("لأي رقم x، الدالة f(x) ترجع رقمًا أكبر من 0")، وليس مجرد مثال واحد. ثالثًا، عند تغيير الكود، غالبًا ما تستمر هذه الاختبارات في العمل دون تعديل لأنها تتحقق من خصائص عامة وليس قيمًا محددة.
proptest هي النظير لمكتبات QuickCheck (Haskell)، Hypothesis (Python)، و FsCheck (.NET). توفر مجموعة غنية من استراتيجيات توليد البيانات (من الأرقام البسيطة إلى الهياكل المعقدة)، وآلية تقليص (shrinkage) لتقليل الأمثلة الفاشلة، والتكامل مع إطار الاختبار الرئيسي لـ Rust وهو cargo test.
2. طريقة التثبيت
لاستخدام proptest، أضفها إلى قسم [dev-dependencies] في ملف Cargo.toml الخاص بك:
[dev-dependencies]
proptest = "1.4"
ثم قم بتنفيذ الأمر:
cargo build
سيتم تحميل المكتبة وتجميعها. يمكنك الآن استخدامها في وحدات الاختبار الخاصة بك.
3. بداية سريعة — مثال عملي بسيط
لنكتب اختبارًا بسيطًا يتحقق من أن الدالة reverse (عكس السلسلة النصية) هي عملية انعكاسية: إذا طبقناها مرتين، نحصل على السلسلة الأصلية.
// src/lib.rs
pub fn reverse(s: &str) -> String {
s.chars().rev().collect()
}
#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;
proptest! {
#[test]
fn test_reverse_involution(s in ".*") {
let reversed = reverse(&s);
let double_reversed = reverse(&reversed);
assert_eq!(s, double_reversed);
}
}
}
قم بتشغيل الاختبار باستخدام الأمر cargo test. ستقوم proptest بتوليد 256 سلسلة عشوائية (العدد الافتراضي) والتحقق من تحقق الخاصية. إذا فشل الاختبار، ستحاول المكتبة العثور على أصغر مثال يكرر الخطأ.
4. أهم الدوال والمكونات
فيما يلي المكونات الرئيسية لمكتبة proptest. جميع الأمثلة تفترض إضافة use proptest::prelude::*; في بداية وحدة الاختبار.
4.1. الماكرو proptest!
التوقيع: proptest! { ... }
الوظيفة: الماكرو الرئيسي الذي يحدد كتلة اختبارات الخصائص. بداخله يمكنك تعريف دوال اختبار مع توليد تلقائي للبيانات.
proptest! {
#[test]
fn test_addition_commutative(a in 0..100i32, b in 0..100i32) {
assert_eq!(a + b, b + a);
}
}