التعامل بفعالية مع الكود الموروث 4 – Unit tests

هذا هو الجزء الرابع من سلسلة (التعامل بفاعلية مع الكود الموروث) والتي نقوم فيها بتلخيص الكتاب الذي يحمل نفس الاسم. يمكنك الاطلاع على كامل مقالات السلسلة من هنا.

تحدثنا في المقالات السابقة عن أهمية الاختبارات tests بشكل عام، واليوم سنخطوا أول خطوة في التفاصيل. عندما وصلت لهذا الجزء في قراءتي للكتاب سألت نفسي كيف كنت أكتب البرامج بدون كتابة tests.


تحدثنا أيضا في المقالة السابقة تحديدًا عن الفرق بين ال regression tests و ال unit tests. أما مقالتنا اليوم ستتناول بشكل أعمق ال Unit tests.

إتفقنا على أن ال tests هي عبارة عن كود يكتب لفحص كود والتأكد من أنه يعمل كما هو متوقع منه. كما أنها تعمل بمثابة شبكة أمان وعقد بين المبرمج و الكود على أنه سيبقى يعمل بنفس الطريقة. وفي حالة تعديل عمل البرنامج أو إصلاح bug ما، ستكون هذه ال tests بمثابة جهاز أمان ينبه المبرمج  في حالة أن التغيرات الجديدة على الكود أدت إلى تغير في عمل الكود القديم.

Unit tests

الفكرة وراء الـ unit tests أنها تقوم بفحص الكود ليس ككل إنما كأجزاء components محددة معزولة عن بعضها، أي تكون هذه الـ components في حالة عزل isolationنعني بهذه ال components – من وجه نظر ال unit tests – أنها عبارة عن أصغر جزء من أجزاء برنامج أو نظام ما.

أي أننا نحتاج لفهم سلوك البرنامج و الطريقة التي يعمل بها، وتقسيمها على أساس سلوكيات مستقلة عن بعضها البعض و صغيرة قدر الإمكان حتى نستطيع كتابة unit test لكل منها على حِدة.

بالنهاية فإن هذه الـ components هي عبارة عن كود. في الشيفرة غرضية التوجه Object oriented code تكون هذه الوحدات units عبارة عن classes. أما في الـشيفرة الإجرائية procedural code تكون عبارة عن الـ functions.

السؤال هنا: هي يمكننا فعلا اختبار function أو class بمعزل عن باقي الكود؟

في ال procedural systems، إختبار function بمعزل عن باقي الكود غالبا صعب. لأن طريقة تسلسل الكود تكون بأن يقوم function باستدعاء function اخر و هكذا حتى أبسط function في ال system.

أما في ال Object oriented systems فإن اختبار ال classes بمعزل عن باقي ال classes ضمن الكود يكون أسهل نوعا ما، لكن الحقيقة المرة أن ال classes لا تعيش بمعزل عن بعضها البعض. كم مرة قمت/ي بكتابة class لا يعتمد على أي class آخر؟

مفهوم ال isolation و أن يكون ال code في هذه ال components صغير قدر الإمكان هي أساسيات في مفهوم ال Unit testing.

نعم, ال tests التي تغطي أجزاء كبيرة من الكود هي مهمة ولكنها تحمل أيضا بعض السلبيات مثل:

1- Error localization:

يصعب تحديد مصدر الخطأ عندما يغطي ال test مساحة كبيرة من ال code. يجب فحص ال variables والعمليات التي تجري عليها على طول تنفيذ الكود و كل الاحتمالات الواردة حتى يتم تحديد مصدر الخطأ. إذًا، كل ما كان الكود الذي يغطيه ال test أكبر كلما تشعبت الاحتمالات و كبرت. نعم، سنقوم بنفس العملية في الـ unit tests لتحديد مصدر أي خطأ ولكن الجهد المبذول حتما أقل لأننا اتفقنا أن ال unit tests تغطي components صغيرة قدر الإمكان.

2- Execution Time

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

ال Unit test الجيد هو السريع في تنفيذه والذي يساعد في تحديد مصدر المشكلة.

خصائص يجب عدم توافرها في الـ Unit tests

بكل وضوح, ال Unit test يجب أن تحترم مايلي:

١-  يجب أن تكون سريعة في تنفيذها، و إلا لا يمكن إعتبارها unit tests.

٢-   لا يجب أن تتخاطب أو تتواصل مع قاعدة البيانات database.

٣-   لا يجب أن تجري أي عمليات على أي شبكة network.

٤- لا يجب أن تجري أي تخاطب مع ال file system.

٥- لا يمكن اعتبارها unit tests في حال كان عليك كمبرمج أن تجري تغيرات محددة على النظام  لجعلها تعمل، مثل تعديل configuration file.

ال test المخالفة للقواعد السابقة ليست سيئة بالطبع,، ولكن لا يمكن اعتبارها unit tests إذا أنها لا تساعد على تحقيق الهدف المرجو من كتابة هذا النوع من الاختبارات.

الخلاصة:

أي test جيد هو test مفيد. ولكن ال unit tests تحديدًا تساعدنا في حماية التفاصيل الصغيرة في البرنامج و التأكد من أنها تعمل كما هو متوقع.

ونتذكر دائما: الـ unit test الجيد يجب أن يكون سريعًا ويساعدنا في تحديد مصدر المشكلة bug بسهولة.

 

حنين عبد الله

مطورة تطبيقات اندرويد, مهتمة بإثراء المحتوى العربي بكل ما يخص البرمجة.   
عنواني على تويتر @haneen0abdallah

Leave a Reply

Your email address will not be published. Required fields are marked *