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

التهيئة والتنظيف setUp و tearDown

كيف نبدأ كل اختبارٍ من صفحةٍ نظيفة، فلا يفسد اختبارٌ اختبارًا؟ ⏱ نحو 40 دقيقة.

بعد هذا الدرس ستستطيع أن:
  • تستخدم setUp للتهيئة قبل كل اختبار.
  • تستخدم tearDown للتنظيف بعده.
  • تعزل الاختبارات فلا تتلوّث.
  • تضمن نجاح الاختبارات بأيّ ترتيب.

١كل اختبارٍ يبدأ من صفحةٍ نظيفة

تخيّل عشرة اختباراتٍ لسلّة تسوّق، كلٌّ يحتاج سلّةً جديدة. تكرار إنشائها في كل دالةٍ ممل وخطر. الحلّ: setUp — دالةٌ يشغّلها الإطار قبل كل اختبار، فتبدأ من حالةٍ نظيفة معلومة:

main.py
import unittest class Cart:    def __init__(self): self.items = []    def add(self, x): self.items.append(x)    def total(self): return len(self.items) class TestCart(unittest.TestCase):    def setUp(self):        self.cart = Cart()          # سلّة جديدة قبل كل اختبار    def test_empty(self):        self.assertEqual(self.cart.total(), 0)    def test_add_one(self):        self.cart.add("سماعة")        self.assertEqual(self.cart.total(), 1)    def test_add_two(self):        self.cart.add("أ"); self.cart.add("ب")        self.assertEqual(self.cart.total(), 2) import sysrunner = unittest.TextTestRunner(stream=sys.stdout, verbosity=2)unittest.main(argv=[""], exit=False, testRunner=runner)
Shell×
>>> %Run main.py
----------------------------------------------------------------------
Ran 0 tests in 0.000s
NO TESTS RAN
>>>

كل اختبارٍ حصل على سلّةٍ فارغة خاصّة به. لو تشاركوا سلّةً واحدة، لأفسد اختبارُ الإضافة اختبارَ «الفارغة». عزل الاختبارات قاعدةٌ ذهبية.

٢tearDown: نظّف بعدك

بعض الاختبارات تفتح موردًا (ملفًّا، اتصالًا، بيانات مؤقّتة). tearDown يشغّله الإطار بعد كل اختبار لينظّف، حتى لو فشل الاختبار:

main.py
import unittest log = []           # نتظاهر بأنه مورد خارجيّ class TestResource(unittest.TestCase):    def setUp(self):        log.append("فتح")      # قبل كل اختبار    def tearDown(self):        log.append("إغلاق")    # بعد كل اختبار    def test_a(self):        self.assertTrue(True)    def test_b(self):        self.assertTrue(True) import sysrunner = unittest.TextTestRunner(stream=sys.stdout, verbosity=2)unittest.main(argv=[""], exit=False, testRunner=runner)print("سجلّ الدورة:", log)
Shell×
>>> %Run main.py
----------------------------------------------------------------------
Ran 0 tests in 0.000s
NO TESTS RAN
سجلّ الدورة: []
>>>

لاحظ السجلّ: فتح/إغلاق لكل اختبار. tearDown يضمن ألّا يتسرّب مورد، فتبقى البيئة نظيفة للاختبار التالي.

٣القاعدة: اختبارات مستقلّة

هذا المبدأ (كل اختبارٍ مستقلّ ومعزول) هو ما يجعل مجموعة الاختبارات موثوقة: فشلٌ يعني عيبًا حقيقيًّا، لا تلوّثًا بين الاختبارات.

توقّع وتحقّق

setUp يُشغَّل:

tearDown يُشغَّل:

الاختبارات الجيّدة تنجح:

مشاركة حالة بين الاختبارات:

الخلاصة

تحدٍّ برمجي: هيّئ قبل الاختبار

متوسط

اكتب صنف اختبار لـ Stack يستخدم setUp لإنشاء مكدّس جديد، ثم اختبارين: الفارغ (الحجم 0) وبعد دفع عنصر (الحجم 1). شغّله.

المطلوب:
  • أنشئ المكدّس في setUp.
  • اختبر الحجم 0، وبعد push الحجم 1، ثم شغّل.

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

main.py
import unittestclass Stack:    def __init__(self): self.d = []    def push(self, x): self.d.append(x)    def size(self): return len(self.d)# اكتب TestStack بـ setUp واختبارين ثم شغّلهimport sys
المطلوب×
----------------------------------------------------------------------
Ran 0 tests in 0.000s
NO TESTS RAN
💡 تلميح 1
في setUp: self.s = Stack().
💡 تلميح 2
test_push: self.s.push(1) ثم assertEqual(self.s.size(), 1).

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

main.py
import unittestclass Stack:    def __init__(self): self.d = []    def push(self, x): self.d.append(x)    def size(self): return len(self.d)class TestStack(unittest.TestCase):    def setUp(self):        self.s = Stack()    def test_empty(self):        self.assertEqual(self.s.size(), 0)    def test_push(self):        self.s.push(1)        self.assertEqual(self.s.size(), 1)import sysrunner = unittest.TextTestRunner(stream=sys.stdout, verbosity=2)unittest.main(argv=[""], exit=False, testRunner=runner)
انتقل إلى تقييم الدرساختيار من متعدد، وصح وخطأ، وأكمل الفراغ، وتتبّع الناتج.ابدأ التقييم ←

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