3.4الاختبارات الآلية (pytest) والتنميط (type hints)
الأساسي في 30 ثانية
- الاختبار تأكيد قابل للتنفيذ : def test_tva(): assert tva(100) == 120 — يكتشف pytest ملفات test_*.py ويشغلها ؛ ونختبر الحدود، لا الاسمي فقط.
- دورة أحمر-أخضر-تنظيف تحمي : اختبار أولا (يفشل)، والحد الأدنى بعدها (ينجح)، والتنظيف أخيرا — كل خطأ مصحح يبدأ بـ اختبار يعيد إنتاجه.
- التلميحات (hints) توثق دون تقييد : def tva(prix: float) -> float — مقروءة، محققة عبر mypy، وتنميط تدريجي على الحدود أولا.
حالة مصغرة متسلسلة — نبيل يثبت أن مبالغه صحيحة
نبيل، محلل بيانات مبتدئ في الجزائر، صحح معدل TVA في حساب مبيعاته وكسر بصمت ثلاثة تقارير : لم ينتبه أحد لأسبوع. كتب اختبارات pytest (اسمي، وسعر سالب يرفع ValueError)، واعتمد دورة أحمر-أخضر-تنظيف، وعلم دواله (prix: float) -> float وتحقق عبر mypy. الانحدار التالي يفشل من أول pytest -q.
الحلقة الأخيرة من سلسلة نبيل — من الوحدة المرتبة إلى البيئة المعزولة حتى الكود المثبت.
1. اختبار pytest : برهان قابل للتنفيذ ودورة
يتحقق الاختبار الآلي تلقائيا من أن جزءا من البرنامج يفعل ما ننتظر، قابل لإعادة التنفيذ في أي وقت : def test_tva(): assert tva(100) == 120. مع pytest، نكتب دوال test_*() بـ assert في ملفات test_*.py، تُطلَق بالأمر pytest. نختبر الاسمي، والحالات الحدية (الفارغ، الصفر، السالب — حيث تعيش الأخطاء) والأخطاء (pytest.raises).
الدورة التي تحمي هي أحمر-أخضر-تنظيف : كتابة الاختبار قبل (يفشل : أحمر)، وترميز الحد الأدنى (ينجح : أخضر)، والتنظيف (refactor). يبدأ كل تصحيح خطأ بـ اختبار يعيد إنتاجه : لن يعود الخطأ أبدا دون تنبيه. يعيد نبيل pytest -q بعد كل تغيير معدل.
2. تلميحات الأنواع (type hints) : توثيق يتحقق
تشير تعليمات الأنواع (type hints) إلى الأنواع المنتظرة : def moyenne(notes: list[float]) -> float. يتجاهلها بايثون عند التنفيذ — يشتغل الكود دونها — لكنها توثق، وتعين المحرر (إكمال تلقائي، كشف) وتيسر الصيانة. تنميط تدريجي : الحدود أولا (API، الدوال المشتركة)، والداخل بعدها.
تتحقق أداة mypy من اتساق التلميحات (hints) دون تنفيذ الكود (تحليل ساكن)، ويفضل في التكامل المستمر. يعلم نبيل دوال الحساب المشتركة في الجزائر، ويختبر الحواف (قائمة فارغة، مبلغ سالب) ويستهدف اختبارات نافعة بدل السباق إلى 100 % تغطية. تلميحات + اختبارات : كود يُعاد قراءته ويثبت.
🔎 مثال ملموس — أول اختبار يحمي الحساب
يؤمن نبيل TVA خاصته : اسمي وحدي وخطأ.
def tva(prix_ht: float, taux: float = 0.2) -> float:
if prix_ht < 0:
raise ValueError("prix negatif")
return prix_ht * (1 + taux)
import pytest
from prix import tva
def test_tva_nominal():
assert tva(100) == 120
def test_tva_negatif():
with pytest.raises(ValueError):
tva(-5)
القراءة : اسمي + حدي + خطأ : الثلاثي الأدنى الذي يحمي.
الدرس : أعد pytest -q بعد كل تغيير معدل.
مفردات القسم
- الاختبار الآلي
- كود يتحقق تلقائيا من أن جزءا من البرنامج يشتغل كما هو منتظر، قابل لإعادة التنفيذ في أي وقت.
مثال بسيط: اختبارات TVA لنبيل المعادة بعد كل تعديل.
ما ليس كذلك: تجربة يدوية منسية بعد يومين.
رد فعل: اختبر الاسمي + الحدود + الأخطاء.
- pytest
- إطار اختبار : دوال test_*() بـ assert في test_*.py، تُطلَق بالأمر pytest.
مثال بسيط: عبارة pytest -q لنبيل بعد كل تغيير.
ما ليس كذلك: طباعات تحقق هالكة بعد الاستعمال.
رد فعل: ملف test_*.py لكل وحدة مختبَرة.
- assert
- يتحقق أن شرطا صحيح، وإلا فشل الاختبار : assert tva(100) == 120.
مثال بسيط: المساواة الاسمية لـ TVA عند نبيل.
ما ليس كذلك: تعليق « يفترض أن يشتغل ».
رد فعل: أكد النتيجة المنتظرة بدقة.
- تلميحات الأنواع (type hints)
- تعليمات الأنواع المنتظرة (a: int) -> str : توثق دون تقييد التنفيذ.
مثال بسيط: عبارة (prix_ht: float, taux: float = 0.2) -> float لنبيل.
ما ليس كذلك: قيد يمنع التنفيذ.
رد فعل: علم الحدود المشتركة أولا.
- mypy
- أداة تتحقق من اتساق التلميحات (hints) دون تنفيذ الكود (تحليل ساكن).
مثال بسيط: التحقق من حسابات نبيل في التكامل المستمر.
ما ليس كذلك: اختبار تنفيذ يعوض التلميحات.
رد فعل: تلميحات + mypy + اختبارات : كود مثبت.
في التطبيق — الاختبار بـ pytest وتعليم الأنواع
- ثبتوا pytest واكتبوا دالة (مثلا tva) ثم اختباراتها في test_prix.py بـ assert.
- أطلقوا pytest : لاحظوا التقرير، وتسببوا في فشل إرادي واقرءوا التشخيص.
- علموا دوالكم : def moyenne(notes: list[float]) -> float.
- أضيفوا اختبار حالة حدية (قائمة فارغة، سعر سالب) مع pytest.raises للخطأ.
نص جاهز للقول — عرض اختباراته (30 ثانية)
« الحسابات مغطاة بـ pytest : اسمي وحدود وأخطاء عبر pytest.raises، ودورة أحمر-أخضر-تنظيف، وpytest -q بعد كل تغيير. الدوال المشتركة معلمة بتلميحات (hints) ومحققة عبر mypy. كل انحدار يفشل قبل بلوغ التقارير. »
يُقال في المراجعة ؛ ويُعرَض الثلاثي اسمي + حدي + خطأ.
نموذج نسخ-لصق — دالة منمطة + اختبارات pytest
def moyenne(notes: list[float]) -> float:
if not notes:
raise ValueError("liste vide")
return sum(notes) / len(notes)
import pytest
from stats import moyenne
def test_moyenne_nominale():
assert moyenne([10.0, 20.0]) == 15.0
def test_moyenne_vide():
with pytest.raises(ValueError):
moyenne([])
مستقل
تكفي ثلاثة اختبارات (اسمي + حدي + خطأ) لتأمين الحسابات الشهرية.
مقاولة صغيرة في الجزائر
يغطي نبيل TVA والمتوسطات قبل إرسال التقارير للمسؤولين.
فريق منتج
فرض pytest -q + mypy في التكامل المستمر لكل دمج.
مبتدئ
هذا الأسبوع : دالة معلمة واختباران، منهما حالة حدية.
✓ ممارسات جيدة
- كتابة الاختبار قبل (أحمر)، ثم الحد الأدنى (أخضر)، ثم التنظيف.
- اختبار الحدود والأخطاء، لا الاسمي فقط.
- تعليم الحدود المشتركة والتحقق عبر mypy.
✗ أخطاء شائعة
- الاختبار بعد (أو أبدا) واكتشاف الانحدار في الإنتاج.
- اختبار الاسمي فقط (الحواف تنكسر أولا).
- استهداف 100 % تغطية كوثن بدل اختبارات نافعة.
النقاط الأساسية
- الاختبارات تثبت أن الكود يشتغل — pytest : test_*() + assert، والأمر pytest.
- أحمر-أخضر-تنظيف : اختبار قبل، والحد الأدنى بعد، والتنظيف — الخطأ = اختبار يعيد إنتاجه.
- التلميحات (hints) توثق الأنواع دون تغيير التنفيذ ؛ وmypy يتحقق منها.
- الحدود + الأخطاء أولا (الفارغ، السالب، الصفر) : هناك تنكسر.
تحدي 48 ساعة — طبّق غدا
غطوا دالة واحدة بـ 3 اختبارات (اسمي + حدي + خطأ) وعلموها بتلميحات.
- اختباراتي تغطي الاسمي والحدي والخطأ.
- أمارس أحمر-أخضر-تنظيف مع كل خطأ.
- دوالي المشتركة معلمة ومحققة.
أسئلة شائعة
أليست كتابة الاختبارات مضيعة للوقت ؟
لا، إنها مربحة : تكشف الاختبارات الانحدار فورا، وتتيح التنظيف دون خوف وتوثق السلوك المنتظر. في مشروع يعيش، يفوق الوقت المكسوب بعدم مطاردة الأخطاء كتابة الاختبارات بكثير.
هل تلميحات الأنواع (type hints) إجبارية ؟
لا، يتجاهلها بايثون عند التنفيذ. لكنها تحسن الإكمال التلقائي وكشف الأخطاء والمقروئية — مستحسنة بقوة ضمن فريق أو في مشروع كبير، وقابلة للتحقق عبر mypy.
ماذا يتحقق الثلاثي الأدنى الجيد من الاختبارات ؟