طَبِّقْهاتعلّم المبدأ، وطبّقه بيدكمقرر 245 · ضمان جودة تطبيقات الويب
الدرس 22 · الوحدة 11: الأدوات في الاختبارات الشاملة

اختبار الانحدار Regression

أصلحتَ شيئًا فكسرتَ آخر؛ كيف نضمن أن القديم ما زال يعمل؟ ⏱ نحو 40 دقيقة.

بعد هذا الدرس ستستطيع أن:
  • تفهم الانحدار وكيف يحدث.
  • تحرس السلوك القديم بإعادة تشغيل اختباراته.
  • تضيف اختبارًا لكل عيبٍ تُصلحه.
  • تعرف اختبار الدخان والانحدار المختار.

١العيب الذي يعود

أصلحت عيبًا، وأضفت ميزة — وفجأةً تعطّل شيءٌ كان يعمل! هذا الانحدار Regression: تغييرٌ جديد يكسر سلوكًا قديمًا. اختبار الانحدار هو إعادة تشغيل الاختبارات السابقة بعد كل تغيير للتأكّد أن ما كان يعمل ما زال يعمل.

هنا تظهر القيمة الكبرى للاختبارات الآلية: مجموعةٌ من مئات الاختبارات تُشغَّل في ثوانٍ بعد كل تعديل، فتكشف أيّ كسرٍ فورًا. بلا اختبارٍ آليّ، كل تغييرٍ مقامرة.

٢كيف يحدث الانحدار؟

انظر: دالةٌ تعمل، نضيف «ميزة» فتكسر حالةً قديمة. مجموعة الاختبارات تمسكها:

main.py
import unittest def price_after_tax(price):    # الإصدار 2: أضفنا تقريبًا، لكنه كسر حالة الصفر!    return round(price * 1.15, 2) or price * 1.15 class TestPrice(unittest.TestCase):    def test_normal(self):        self.assertEqual(price_after_tax(100), 115.0)    def test_zero(self):        self.assertEqual(price_after_tax(0), 0.0)     # اختبار قديم يحرس الصفر import sysunittest.main(argv=[""], exit=False, testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))
Shell×
>>> %Run main.py
----------------------------------------------------------------------
Ran 0 tests in 0.000s
NO TESTS RAN
>>>

الاختبار القديم test_zero هو حارس الانحدار: لو كسر تغييرٌ مستقبليّ حالة الصفر، لصرخ فورًا. كل عيبٍ تُصلحه، أضف اختبارًا يمنع عودته.

٣اختبار الدخان والاختيار

مجموعة الانحدار قد تكبر. استراتيجياتٌ عملية:

الاستراتيجيةمتى
اختبار الدخان Smokeقبل كل شيء: حفنة اختباراتٍ للوظائف الحرجة (هل يعمل أصلًا؟)
انحدار كامل Fullقبل الإصدار الكبير: كل الاختبارات
انحدار مختار Selectiveشغّل ما يمسّه التغيير فقط (أسرع)

توقّع وتحقّق

عودة عيبٍ قديم بعد تغييرٍ جديد:

اختبار الانحدار:

حفنة اختباراتٍ للوظائف الحرجة:

عند إصلاح عيب:

الخلاصة

تحدٍّ برمجي: احرس ضدّ العودة

متقدم

الدالة apply_coupon أُصلِحت لتتعامل مع القسيمة الفارغة. اكتب اختبارين يحرسان: قسيمة صحيحة تخصم 10، وقسيمة فارغة لا تخصم. شغّلهما.

المطلوب:
  • تحقّق أن apply_coupon(100, "SAVE")==90.
  • تحقّق أن apply_coupon(100, "")==100. شغّل.

ابدأ من هذا الكود، واضغط ▶ شغّل هنا لتكتب حلّك وتجرّبه مباشرة:

main.py
import unittestdef apply_coupon(price, code):    return price - 10 if code else price# اكتب اختبارين (قسيمة صحيحة وفارغة) ثم شغّلimport sys
المطلوب×
----------------------------------------------------------------------
Ran 0 tests in 0.000s
NO TESTS RAN
💡 تلميح 1
test_valid: apply_coupon(100, "SAVE") == 90.
💡 تلميح 2
test_empty: apply_coupon(100, "") == 100 يحرس العيب المُصلَح.

حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.

main.py
import unittestdef apply_coupon(price, code):    return price - 10 if code else priceclass TestCoupon(unittest.TestCase):    def test_valid(self):        self.assertEqual(apply_coupon(100, "SAVE"), 90)    def test_empty(self):        self.assertEqual(apply_coupon(100, ""), 100)import sysunittest.main(argv=[""], exit=False, testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))
انتقل إلى تقييم الدرساختيار من متعدد، وصح وخطأ، وأكمل الفراغ، وتتبّع الناتج.ابدأ التقييم ←

📝 معلم؟ أرسل ملاحظة للمؤلف عن هذا الدرس