Rust / المتوسط / الدرس 12
الاختبار والتصحيح والبناء القابل للتكرار
حوّل العقود إلى اختبارات حدود وأعد الفشل بمعلومات بناء دقيقة واختر أدوات تجيب عن سؤال محدد.
في هذه الصفحة
أهداف الدرس
- تمييز اختبارات الوحدة والتكامل والتوثيق.
- فحص النجاح وفئات الفشل وحفظ الحالة.
- فصل أدوات التصحيح العادية عن أدوات nightly الاختيارية.
اختبار السلوك دون نسخ التنفيذ
يقدم الاختبار المفيد مدخلات ويفحص العقد بدل تكرار خوارزمية الدالة. غط الفراغ والحدود والرفض والحالة اللاحقة. تبقى assert فعالة في بناء الإصدار المعتاد، وقد تُعطل debug_assert وفق الإعداد. يستخدم المثال تأكيدات كبرنامج تحقق صغير. توضع الاختبارات الفعلية عادة في وحدة اختبار أو ملف تكامل وتُشغّل بـcargo test. لا تظهر رسالة النجاح إلا بعد كل الفحوص.
إبقاء الحساب آمنًا عند حدوده
تقرب دالة الدفعات العد غير السالب لأعلى بخارج وبقية، وتتجنب count + width - 1 الذي قد يفيض قبل القسمة. يعود العرض صفرًا بـNone قبل الحساب. يبقى أقصى u32 آمنًا لأن العرض واحد بلا بقية، وتترك العروض الأكبر مجالًا للوحدة الإضافية. تميّز التأكيدات الفراغ والمضاعف والبقية والعرض الفاسد، وتبقى مفيدة إذا تغير التنفيذ.
fn batches(count: u32, width: u32) -> Option<u32> {
if width == 0 { return None; }
Some(count / width + u32::from(count % width != 0))
}
fn main() {
assert_eq!(batches(0, 4), Some(0));
assert_eq!(batches(8, 4), Some(2));
assert_eq!(batches(9, 4), Some(3));
assert_eq!(batches(2, 0), None);
println!("4 cases passed");
}
4 cases passed
لا يطبع السطر إلا بعد نجاح التأكيدات، وتمثل None عرضًا فاسدًا بدل panic قسمة على صفر.
اختيار طبقة ترى الالتزام
تعيش اختبارات الوحدة بجانب التنفيذ وتصل للعناصر الخاصة عبر وحدة اختبار فرعية مناسبة. تعمل اختبارات tests كوحدات crate مستقلة على الواجهة العامة، وتفحص اختبارات التوثيق الأمثلة المنشورة. اختر الطبقة القادرة على رؤية الالتزام. يفحص المثال الثاني العضوية بالبحث الثنائي لقيمة موجودة وغائبة داخلية وشريحة فارغة. لا يثبت موضع الإدراج المساواة، فتحفظ الحالات الفرق. يجب أن تستوفي المدخلات شرط الترتيب.
fn contains(sorted: &[u32], target: u32) -> bool {
sorted.binary_search(&target).is_ok()
}
fn main() {
let values = [2, 5, 8];
assert!(contains(&values, 5));
assert!(!contains(&values, 6));
assert!(!contains(&[], 1));
println!("3 searches passed");
}
3 searches passed
يحدد الغلاف العضوية بنجاح binary_search لا بمجرد موضع مرشح غير فارغ.
حفظ حالة مصغرة لإعادة الفشل
سجّل الإدخال وإصدار المصدر وrustc وإصدار اللغة والهدف والميزات والأمر كاملًا. اختزل الحالة دون إزالة الفشل. تشرح rustc --explain الرمز وتوضح مواقع التشخيص أصل النقل أو الاستعارة واستعمالها اللاحق. استخدم معلومات التصحيح والتتبعات ومنقّح المنصة أثناء التنفيذ. سجّل حالة مفيدة دون أسرار. قد تتداخل اختبارات البيئة والملفات والحالة العامة عند التوازي؛ اعزل الموارد ولا تفترض أن المجدول يسلسلها.
الأدوات تقدم أدلة بحدود
يساعد cargo fmt وClippy على الاتساق والمراجعة عند تثبيت مكوناتهما، ولا تثبت التحذيرات الصحة كاملة. تكشف Miri أخطاء سلوك غير معرّف كثيرة في المسارات المنفذة، وتحتاج nightly مدعومة ولا تمثل كل التفاعلات الخارجية. تعتمد المطهّرات أيضًا على الهدف والأدوات. يستخدم تحقق المقرر Rust مستقرة وأمثلة قياسية دون اشتراط الأدوات الاختيارية ضمنيًا. بعد نجاح الإصلاح احفظ اختبار منع العودة ولا تكرر فحوصًا بعيدة دون سبب.
الأخطاء الشائعة وإصلاحها
اختبارات ناجحة تفوت إدخالًا مشوهًا.
- لماذا يحدث؟
- غُطيت حالات النجاح العادية فقط.
- كيف تصلحه؟
- أضف حالات الرفض والحدود وحفظ الحالة.
- كيف تتجنب تكراره؟
- اشتق الاختبارات من العقد كاملًا.
اختبارات متوازية تؤثر في بعضها.
- لماذا يحدث؟
- تشارك موارد خارجية أو حالة عامة قابلة للتعديل.
- كيف تصلحه؟
- استخدم موارد مؤقتة معزولة ومزامنة صريحة.
- كيف تتجنب تكراره؟
- وثّق الحالة المشتركة غير القابلة للتجنب.
فشل أداة تشخيص nightly على stable.
- لماذا يحدث؟
- لم تُذكر متطلبات الأداة الاختيارية.
- كيف تصلحه؟
- استخدم إعدادًا مدعومًا أو فحصًا متوافقًا مع stable.
- كيف تتجنب تكراره؟
- افصل الفحوص الأساسية عن التشخيص الاختياري.
اختبر فهمك
1. أضف batches(1, 4) وbatches(u32::MAX, 1) وفسّر الخطأ المختلف الذي تكشفه كل حالة.
اعرض الحل المشروح
النتيجتان Some(1) وSome(u32::MAX). تكشف الأولى القسمة المقربة لأسفل وحدها، وتكشف القصوى صيغة تقريب تضيف إزاحة معرضة للفيض. يفحص الاختباران العقد دون إلزام التنفيذ بخارج وبقية تحديدًا.
2. لا يظهر عيب إلا مع تركيبة ميزات Cargo معينة. حدّد الأدلة وموضع اختبار منع العودة.
اعرض الحل المشروح
سجّل أعلام الميزات والإعداد الافتراضي والهدف والإصدار والمترجم مع إدخال مصغر. أضف اختبارًا يترجم بتلك التركيبة المدعومة وأدرج أمره في الفحوص. إذا عبر العيب واجهة عامة فقد يكشفه اختبار تكامل. لا يكفي تشغيل افتراضي محلي وحده.
أهم ما تعلمته
- اختبر الحدود والرفض والحالة الناتجة.
- اجعل الفشل قابلًا للإعادة عبر إعدادات البناء.
- ميّز الأدوات المستقرة الأساسية من التشخيص الاختياري.