AzLearn

أساسيات unittest

unittest Basics

مفهوم ~18 دقيقة

أساسيات unittest — unittest Basics

قبل أن يُكتب أي كود في مشروع جاد، يُكتب اختبار. هذه الفلسفة تحمي كل تغيير تجريه لاحقاً. Python تأتي بحزمة unittest في المكتبة المعيارية — لا تحتاج تثبيت أي شيء، فقط import unittest وتبدأ.

مفهوم الاختبار الآلي

الاختبار الآلي (Automated Test) هو كود يتحقق من أن كوداً آخر يتصرف بالشكل المتوقع. عوضاً عن تشغيل البرنامج يدوياً وتفحّص المخرجات بعينيك، تكتب مرة واحدة توقعاتك وتشغّل الأداة كلما احتجت.

الفائدة الحقيقية تظهر عند التعديل: عندما تُعيد كتابة دالة أو تُضيف ميزة، تشغّل الاختبارات وتعرف على الفور إذا كسرت شيئاً كان يعمل. بدون اختبارات، كل تغيير يحتمل كسر أجزاء لم تُلاحظها.

بنية اختبار unittest

نمط unittest يدور حول ثلاثة عناصر:

  1. TestCase — كلاس ترث منه اختباراتك (unittest.TestCase)
  2. دوال الاختبار — كل دالة تبدأ بـtest_ تُعامَل كاختبار مستقل
  3. Assertions — دوال تتحقق من التوقعات، مثل assertEqual وassertTrue
import unittest

class TestMyFunction(unittest.TestCase):
    def test_something(self):
        result = my_function()
        self.assertEqual(result, expected_value)

أول اختبار حقيقي

main.go

لاحظ الناتج: كل دالة اختبار تُبلَّغ منفصلاً. OK تعني نجاح. لو فشل اختبار، يُظهر FAIL مع سبب التفصيلي.

setUp و tearDown

أحياناً تحتاج إعداداً مشتركاً قبل كل اختبار — قاعدة بيانات مؤقتة، كائن مهيّأ، ملف اختبار. setUp تُشغَّل قبل كل اختبار، وtearDown تُشغَّل بعد كل اختبار حتى لو فشل.

هذا يضمن أن كل اختبار يبدأ بحالة نظيفة ولا يتأثر بنتائج الاختبارات السابقة.

main.go

Assertions الشائعة

unittest.TestCase توفّر مجموعة واسعة من دوال التحقق. إليك الأكثر استخداماً:

الدالةمتى تستخدمها
assertEqual(a, b)عندما تتوقع أن a == b
assertNotEqual(a, b)عندما تتوقع أن a != b
assertTrue(x)عندما تتوقع أن x صحيحة (truthy)
assertFalse(x)عندما تتوقع أن x خاطئة (falsy)
assertIsNone(x)عندما تتوقع x is None
assertIsNotNone(x)عندما تتوقع x is not None
assertIn(a, b)عندما تتوقع أن a in b
assertRaises(exc)عندما تتوقع رفع استثناء
assertAlmostEqual(a, b)للأرقام العشرية (تتجاهل الفارق الصغير)
main.go

استخدام assertRaises بشكل صحيح

assertRaises له أسلوبان: كـcontext manager (الأوضح)، أو كدالة مباشرة.

# الأسلوب الأوضح: context manager
def test_invalid_input(self):
    with self.assertRaises(ValueError) as ctx:
        divide(5, 0)
    # يمكن التحقق من رسالة الخطأ
    self.assertIn("صفر", str(ctx.exception))

# الأسلوب البديل: أقل وضوحاً
def test_invalid_input_alt(self):
    self.assertRaises(ValueError, divide, 5, 0)

الأسلوب الأول أفضل لأنه يُتيح التحقق من رسالة الاستثناء أيضاً.

تشغيل الاختبارات في مشروع حقيقي

في مشروع حقيقي، الاختبارات في ملفات منفصلة:

my_project/
├── calculator.py       # الكود الأصلي
└── test_calculator.py  # الاختبارات

ثم تشغّل من Terminal:

# شغّل اختبارات ملف واحد
python -m unittest test_calculator

# شغّل كل الاختبارات في المجلد
python -m unittest discover

# مع تفاصيل — verbose
python -m unittest -v test_calculator

الخيار -m unittest يجعل Python تشغّل الوحدة كأداة سطر أوامر.

تنظيم الاختبارات — أفضل الممارسات

  1. اسم واضح للاختبارtest_add_two_positive_numbers أفضل من test1
  2. اختبار واحد يختبر فكرة واحدة — لا تختبر خمسة سلوكيات في دالة واحدة
  3. اختبر الحالات الحدية — صفر، قيمة فارغة، قيمة سالبة، قيمة أقصى
  4. لا تعتمد ترتيب التشغيل — كل اختبار مستقل عن الآخر
  5. رسالة خطأ واضحةassertEqual(result, 5, "يجب أن يكون الجمع 5") يساعد عند الفشل
تحدي — Challenge