目次
1. ما هو unittest في بايثون؟
unittest
هو إطار اختبار وحدة موجود في مكتبة بايثون القياسية، وهو أداة مهمة لضمان جودة الكود. يتيح للمطورين اختبار كل جزء من الكود بشكل منفصل، ويساعد على اكتشاف الأخطاء مبكرًا. كما يساعد في التأكد من أن تغييرات الكود لا تُفسد الوظائف الحالية أثناء التطوير المستمر.أهمية اختبار الوحدة
مع تعقّب الكود، يصبح من الصعب التحقق مما إذا كانت الأجزاء المختلفة تتعاون بشكل صحيح. من خلال إدخال اختبارات الوحدة، يصبح من السهل منع الأخطاء غير المتوقعة الناتجة عن تغييرات صغيرة، وبالتالي الحفاظ على استقرار البرنامج ككل.2. الاستخدام الأساسي لـ unittest
unittest
الأساس هو إنشاء فئة ترث من unittest.TestCase
وتعريف طرق الاختبار داخلها. داخل طريقة الاختبار، يتم استخدام أساليب التأكيد مثل assertEqual()
لمقارنة النتيجة المتوقعة بالنتيجة الفعلية.مثال اختبار أساسي
الكود التالي هو مثال بسيط لاختبار الدالةadd(a, b)
.import unittest
# كود الاختبار المستهدف
def add(a, b):
return a + b
# فئة الاختبار
class TestAddFunction(unittest.TestCase):
def test_add_integers(self):
result = add(2, 3)
self.assertEqual(result, 5)
if __name__ == '__main__':
unittest.main()
في هذا الكود، يتم اختبار ما إذا كانت الدالة add()
تعمل بشكل صحيح. طريقة assertEqual()
تتحقق من أن القيمة المتوقعة والنتيجة الفعلية متساويتان. بهذه الطريقة، يمكن التأكد من أن الدالة تعمل بشكل صحيح عبر حالات متعددة.توسيع الاختبار
يمكنك استخدام طرق اختبار متعددة لاختبار سلوك الدالة مع مدخلات مختلفة. على سبيل المثال، يمكن اختبار الأعداد العشرية أو دمج السلاسل.def test_add_floats(self):
result = add(2.5, 3.5)
self.assertAlmostEqual(result, 6.0, places=2)
def test_add_strings(self):
result = add("Hello, ", "World!")
self.assertEqual(result, "Hello, World!")
بهذه الطريقة، من خلال اختبار سلوك الدالة مع أنواع بيانات مختلفة، يمكنك التأكد من أن الدالة تعمل بشكل صحيح في مختلف السيناريوهات.
3. طريقة استخدام setUp() و tearDown()
لتنفيذ عمليات معينة تلقائيًا قبل وبعد الاختبار، استخدم طرقsetUp()
و tearDown()
. هذا يتيح لك إعداد ما يلزم قبل تشغيل الاختبار وإجراء التنظيف بعد انتهاء الاختبار.مثال setUp()
setUp()
طريقة تُستدعى دائمًا قبل تنفيذ كل طريقة اختبار، ويمكن من خلالها تجميع عمليات التهيئة المشتركة.def setUp(self):
self.temp_value = 42
مثال tearDown()
tearDown()
تُنفّذ بعد كل طريقة اختبار، وتقوم بعمليات ما بعد التنفيذ وإطلاق الموارد. على سبيل المثال، يمكن استخدامها لفصل اتصال قاعدة البيانات أو حذف الملفات المؤقتة.def tearDown(self):
self.temp_value = None
بهذه الطريقة، يمكنك تقليل التكرار في شفرة الاختبار والحفاظ على شفرة أنظف.4. اختبار الاعتماديات باستخدام الموك
إذا كان الكود الذي يُختبر يعتمد على موارد خارجية (مثل قاعدة البيانات أو API)، يمكن تحسين سرعة تنفيذ الاختبار وإجراء اختبارات قابلة للتنبؤ من خلال استبدال الجزء المتعتمد بالموك. باستخدام وحدةunittest.mock
في بايثون، يمكن تحقيق ذلك بسهولة.مثال على الموك
في الشيفرة التالية، يتم استبدال الدالة التي تستغرق وقتًا طويلاًtime_consuming_function()
بالموك.from unittest.mock import patch
class TestAddFunction(unittest.TestCase):
@patch('my_module.time_consuming_function')
def test_add_with_mock(self, mock_func):
mock_func.return_value = 0
result = add(2, 3)
self.assertEqual(result, 5)
في هذا المثال، يتم تنفيذ الاختبار دون استدعاء time_consuming_function
باستخدام الموك. وهذا يختصر وقت الاختبار مع الحصول على نتائج دقيقة.
5. معالجة الاستثناءات والتأكيد المخصص
unittest
يمكن اختبار معالجة الاستثناءات أيضًا. على سبيل المثال، للتحقق من حدوث الاستثناء بشكل صحيح في حالة معينة، استخدم assertRaises()
.اختبار معالجة الاستثناءات
في المثال التالي، يتم التأكد من حدوثZeroDivisionError
.def test_divide_by_zero(self):
with self.assertRaises(ZeroDivisionError):
divide(1, 0)
هذا الكود يختبر أن divide(1, 0)
ينتج عنه ZeroDivisionError
عند استدعائه.إنشاء تأكيد مخصص
في الحالات التي لا يمكن للتأكيد القياسي التعامل معها، يمكنك إنشاء طريقة تأكيد مخصصة خاصة بك.def assertIsPositive(self, value):
self.assertTrue(value > 0, f'{value} is not positive')
باستخدام التأكيد المخصص، يمكنك التعامل مع سيناريوهات اختبار أكثر تحديدًا.6. وظيفة اكتشاف الاختبارات في unittest
unittest
باستخدام وظيفة اكتشاف الاختبارات يمكنك العثور تلقائيًا على جميع ملفات الاختبار داخل المشروع وتشغيلها. هذه الميزة مفيدة بشكل خاص في المشاريع الكبيرة.كيفية استخدام اكتشاف الاختبارات
لتنفيذ اكتشاف الاختبارات، استخدم الأمر التالي.python -m unittest discover
وبهذا يتم تشغيل جميع ملفات test_*.py
داخل الدليل المحدد. إذا كنت تريد تحديد ملفات أو أدلة، استخدم الخيارات كما يلي.python -m unittest discover -s tests -p "test_*.py"
باستخدام هذه الميزة، يمكنك تجنب الحاجة لتحديد ملفات الاختبار يدويًا، وإدارة الاختبارات بفعالية حتى في المشاريع الكبيرة.7. نصائح لتحسين الأداء باستخدام unittest
إذا كان سرعة تنفيذ الاختبارات بطيئة، فإن كفاءة التطوير تتراجع. هنا نقدم بعض النصائح لتحسين أداء الاختبارات باستخدامunittest
.تحسين I/O للملفات
الاختبارات التي تتطلب قراءة وكتابة الملفات يمكن تسريعها بمعالجتها في الذاكرة. باستخدامStringIO
يمكن إنشاء كائن يتصرف كملف في الذاكرة، مما يسمح بتجنب I/O على القرص.from io import StringIO
class TestFileOperations(unittest.TestCase):
def test_write_to_memory(self):
output = StringIO()
output.write('Hello, World!')
self.assertEqual(output.getvalue(), 'Hello, World!')
بهذه الطريقة، حتى الاختبارات التي تحتاج إلى الوصول إلى الملفات يمكنها تحسين سرعتها بشكل كبير.استخدام Mock
لتقليل الوصول إلى الموارد الخارجية، يمكن تسريع الاختبارات باستخدام Mock. هذا يسمح بتجنب التأخير في الشبكة أو قاعدة البيانات وتقليل وقت تنفيذ الاختبارات. في المثال التالي، يتم استبدال استدعاءات API بـ Mock.from unittest.mock import MagicMock
class TestApiCall(unittest.TestCase):
def test_api_response(self):
mock_api = MagicMock(return_value={'status': 'success'})
response = mock_api()
self.assertEqual(response['status'], 'success')
بهذه الطريقة، يمكن اختبار الوظائف دون الاعتماد على الموارد الخارجية، مما يخلق بيئة اختبار أسرع وأكثر استقرارًا.8. الملخص والخطوة التالية
في هذه المقالة، شرحنا بشكل واسع أساسيات اختبار الوحدة باستخدامunittest
في بايثون، بدءًا من الأساسيات، واستخدام إعداد وإلغاء الإعداد (setUp/tearDown)، واختبار الاعتمادات باستخدام الموك، وحتى تقنيات تحسين أداء الاختبار.ملخص النقاط الرئيسية
- طريقة الاستخدام الأساسية: ورث من
unittest.TestCase
واستخدم أساليب التأكيد لإنشاء الاختبارات. - setUp() / tearDown(): من خلال تجميع وإدارة المعالجة المشتركة قبل وبعد الاختبار، يتم تحسين قابلية إعادة استخدام الكود وقابليته للقراءة.
- استخدام الموك: يتيح اختبار الوظائف دون الاعتماد على موارد خارجية، مما يحسن كفاءة الاختبار بشكل كبير.
- اكتشاف الاختبارات: ميزة مفيدة تسهل إدارة الاختبارات في المشاريع الكبيرة.
- تقنيات تحسين الأداء: من خلال المعالجة في الذاكرة واستخدام الموك، يمكن تقليل وقت تنفيذ الاختبارات.
الخطوة التالية
بعد إتقان أساسياتunittest
، جرب طرق اختبار أكثر تقدمًا. على سبيل المثال، يمكنك إجراء “اختبار معلمَّى” يختبر بيانات إدخال متعددة في وقت واحد، أو استخدام أدوات التغطية للتحقق من نطاق اختبار الكود، مما يعزز استراتيجية الاختبار للمشروع بأكمله. كما يمكنك النظر إلى أطر اختبار أخرى مثل pytest
لتوسيع الخيارات وفقًا للاستخدام. الاختبار هو عنصر مهم في التطوير. اكتشف الأخطاء مبكرًا وحافظ على جودة الكود من خلال دمج الاختبارات بنشاط.