اختبارات وحدة بايثون: بداية سريعة

تم إعداد ترجمة لهذه المقالة خصيصًا لطلاب دورة Python QA Engineer .


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

في هذه المقالة ، سأوضح الفكرة الأساسية لاختبار الوحدة في فصل واحد. في الممارسة العملية ، سيتعين عليك كتابة العديد من حالات الاختبار وإضافتها إلى مجموعة الاختبار وتشغيلها معًا. ستتم مناقشة إدارة حالة الاختبار في المقالة التالية.

اليوم سوف نركز على اختبار الواجهة الخلفية. بمعنى ، قام المطور بتطبيق بعض المشاريع وفقًا للمواصفات (على سبيل المثال ، Calculator.py) ، ومهمتك هي التأكد من أن الكود الذي تم تطويره TestCalculator.py حقًا (على سبيل المثال ، باستخدام TestCalculator.py ).

لنفترض أنك كتبت فئة الحاسبة لأداء الوظائف الحسابية الأساسية: الجمع والطرح والضرب والقسمة.

رمز هذا هنا ( Calculator.py ):

 #A simple calculator class Calculator: #empty constructor def __init__(self): pass #add method - given two numbers, return the addition def add(self, x1, x2): return x1 + x2 #multiply method - given two numbers, return the #multiplication of the two def multiply(self, x1, x2): return x1 * x2 #subtract method - given two numbers, return the value #of first value minus the second def subtract(self, x1, x2): return x1 - x2 #divide method - given two numbers, return the value #of first value divided by the second def divide(self, x1, x2): if x2 != 0: return x1/x2 

أريد الآن إجراء اختبار وحدة لفهم أن الوظيفة في الفصل أعلاه تعمل كما هو مخطط لها.

بيثون عادة ما يأتي مع الحزمة unittest . إذا لم يكن موجودًا على نظامك ، فاستخدم النقطة لتثبيته.

يحتوي اختبار الوحدة على الهيكل التالي:



setUp() و tearDown() هي طرق قياسية تأتي مع إطار unittest (يتم تعريفها في فئة unittest.TestCase). بناءً على حالة الاختبار الخاصة بك ، يمكنك تجاوز أو عدم تجاوز هاتين الطريقتين افتراضيًا.

حان الوقت لإلقاء نظرة على رمز حالة الاختبار. هنا هو ملف TestCalculator.py .

 import unittest from Calculator import Calculator #Test cases to test Calulator methods #You always create a child class derived from unittest.TestCase class TestCalculator(unittest.TestCase): #setUp method is overridden from the parent class TestCase def setUp(self): self.calculator = Calculator() #Each test method starts with the keyword test_ def test_add(self): self.assertEqual(self.calculator.add(4,7), 11) def test_subtract(self): self.assertEqual(self.calculator.subtract(10,5), 5) def test_multiply(self): self.assertEqual(self.calculator.multiply(3,7), 21) def test_divide(self): self.assertEqual(self.calculator.divide(10,2), 5) # Executing the tests in the above test case class if __name__ == "__main__": unittest.main() 

على الرغم من أن هذا ليس ضروريًا ، ولكن كقاعدة عامة أدعو فئة الاختبار باستخدام اختبار البادئة (في حالتنا TestCalculator). أحد المتطلبات الرئيسية في هذه الفئة هو وجود الطبقة الفائقة unittest.TestCase .

عند تنفيذ حالة الاختبار هذه ، يتم تنفيذ طريقة setUp () أولاً. في حالتنا ، نقوم ببساطة بإنشاء كائن من الحاسبة الصفية وحفظه كسمة للفئة. هناك عدة طرق افتراضية أخرى في الفصل الأصل ، والتي سنناقشها لاحقًا.

في الوقت الحالي ، كل ما ستفعله هو كتابة طرق test_xxx لاختبار كل طريقة في فئة الحاسبة. يرجى ملاحظة أن جميع طرق الاختبار تبدأ بالبادئة test_ . هذا يخبر بيثون باستخدام إطار unittest أن هذه هي طرق الاختبار.

في كل طريقة من طرق الاختبار ، استخدمت طريقة assertEqual للتحقق مما إذا كانت طرق الحاسبة تُرجع القيمة المتوقعة. إذا كانت قيمة الإرجاع مساوية للقيمة المتوقعة ، فسوف ينجح الاختبار ، وإلا فإنه يفشل.

هناك العديد من أساليب assert المضمنة التي سنتحدث عنها لاحقًا.

السطر الأخير في الكود أعلاه يطلق فقط حالة اختبار TestCalculator . ينفذ كل طريقة اختبار محددة داخل الفصل وتعيد النتيجة.

 python TestCalculator.py -v 


سترى استنتاج مشابه لما يلي:

 test_add (__main__.TestCalculator) ... ok test_divide (__main__.TestCalculator) ... ok test_multiply (__main__.TestCalculator) ... ok test_subtract (__main__.TestCalculator) ... ok -------------------------------------------------------------------- Ran 4 tests in 0.000s OK 

ماذا لو كان هناك شيء لا يعمل كما هو متوقع؟ دعنا نغير القيمة المتوقعة لـ test_divide من 5 إلى 6 (5 هي القيمة الصحيحة ، والآن سنرى ما سيحدث إذا فشلت. ليس هذا خطأ في التعليمات البرمجية المصدر ، ولكن خطأ في مجموعة الاختبار ، قد يكون لديك أيضًا أخطاء في مجموعات الاختبار ، لذلك دقق دائمًا اختبار البرامج النصية للأخطاء!)

 import unittest from Calculator import Calculator #Test cases to test Calulator methods #You always create a child class derived from unittest.TestCase class class TestCalculator(unittest.TestCase): #setUp method overridden from the parent class TestCase def setUp(self): self.calculator = Calculator() ... def test_divide(self): self.assertEqual(self.calculator.divide(10,2), 6) # Executing the tests in the above test case class if __name__ == "__main__": unittest.main() 

عند تشغيل حالة الاختبار هذه ، ستحصل على النتيجة التالية:

 test_add (__main__.TestCalculator) ... ok test_divide (__main__.TestCalculator) ... FAIL test_multiply (__main__.TestCalculator) ... ok test_subtract (__main__.TestCalculator) ... ok ==================================================================== FAIL: test_divide (__main__.TestCalculator) -------------------------------------------------------------------- Traceback (most recent call last): File "TestCalculator.py", line 23, in test_divide self.assertEqual(self.calculator.divide(10,2), 6) AssertionError: 5.0 != 6 -------------------------------------------------------------------- Ran 4 tests in 0.001s FAILED (failures=1) 

تقول هنا أن 3 من أصل 4 اختبارات كانت ناجحة ، ولكن فشل واحد. في سيناريو حقيقي ، يُفترض أن حالة الاختبار الخاصة بك صحيحة ، وبهذه الطريقة تساعد في تحديد وظيفة لا يتم تنفيذها بشكل صحيح.

Source: https://habr.com/ru/post/ar481806/


All Articles