إنجاز مشاريع وبرامج خالية من الأخطاء وتعمل على النحو المتوقع في جميع السيناريوهات والحالات الممكنة، من أهم الأولويات لدى المطورين والمبرمجين بجميع تخصصاتهم.
قد لا يوجد هناك أي برنامج (خصوصا إذا كان كبيرا ومعقدا) يكون خاليا من الأخطاء، هذا أمر طبيعي في عالم البرمجة حتى عند أكبر الشركات التقنية في العالم التي تمتلك مبرمجين ومهندسين على أعلى مستوى.
لا يمكن لتطبيق معين أن يبلغ درجة الكمال، ولكن المطور يجب عليه دائما أن يسعى لهذا الكمال عن طريق تصميم برامج خالية قدر المستطاع من الأخطاء سواء منها البديهية أو التي تظهر في سيناريوهات معينة ونادرة.
على سبيل المثال، كم من مرة وأنتم تلعبون في لعبة FIFA اختبرتم أخطاء برمجية تبدو غير منطقية، كأن تسدد ركلة الجزاء في اتجاه الحارس وعوض أن يمسكها بيده تمر من بين رجليه دون أن يحرك ساكنا، والمعلق يقول بأن الكرة بين يدي الحارس ! :)
Please, just look at this penalty my goalkeeper didn't save. 🙈 #FUTChampions pic.twitter.com/Nz3y3sENKh
— Nick Akerman (@Nakerman) 5 octobre 2018
مطور لعبة فيفا هي شركة EA SPORTS الذائعة الصيت والتي لديها مجموعة من أمهر مهندسي ومطوري الألعاب في العالم، ومع ذلك هناك أخطاء وهناك عيوب. ولكن المهم هو أن الشركة تسعى لإنتاج ألعاب خالية من الأخطاء وتنجز عددا كبيرا من الإختبارات عليها قبل إطلاقها للسوق، وإن ظهرت فيما بعد عيوب في البرنامج فإنه يتم إصلاحها عن طريق إصدار ما يعرف بال Patches، وهذا موجود كذلك في مشاريع الويب خاصة منها مفتوحة المصدر مثل ووردبريس.
ماذا يعني اختبار برنامج ما ؟
ببساطة اختبار برنامج معلوماتي يعني التأكد من أنه يعمل بالشكل المتوقع من دون مفاجآت.
عندما يقوم المطور عادة بتطوير برنامج ما فإنه يقوم في الحقيقية بتحويل فكرة ما إلى واقع، قد تكون هذه فكرته أو فكرة شخص أو كيان آخر، في العادة نسميه العميل أو الزبون.
تنفيذ الفكرة قد ينطوي كما قلنا على عدد من الأخطاء، وذلك يكون راجعا لأسباب عدة من بينها :
- العميل لم يقم بإيصال أفكاره واحتياجاته كما يجب، أو المطور لم يفهم جيدا المطلوب منه. أيا يكن، في النهاية سيكون لدينا برنامج لا يستجيب لما هو منتظر منه.
- ارتكاب عدد من الأخطاء في الكود، مما يتسبب في تعطل البرنامج بكامله أو أجزاء منه.
- في أحيان أخرى، قد يعمل البرنامج بشكل جيد إلا في حالات معينة. مثلا يمكن لبرنامج مثل الآلة الحاسبة أن يعمل بشكل ممتاز إلا في حالة القسمة على صفر، لأنها لم تكن في حسبان المطور :)
الأسباب التي تهمنا في هذا المقال هي المرتبطة بالشفرة المصدرية نفسها، أما مشكل التواصل مع العملاء وتحديد الإحتياجات فذلك موضوع آخر قائم بذاته.
للتأكد من أن شفرتنا البرمجية خالية من الأخطاء والتعارضات، يجب أن نخضعها لإختبارات نسميها برمجية أو أوتوماتيكية، لأنها تتم بشكل آلي ولا علاقة لها بالإختبارات اليدوية التي اعتدنا القيام بها عند نقوم بتجربة برنامج ما على المتصفح أو واجهة العميل أيا كان.
الإختبار اليدوي مطلوب ولكن غير كافي لأننا سنكون مجبرين على تجربة كافة أو معظم وظائف التطبيق في كل مرة نقوم ببرمجة وظيفة جديدة، وذلك للتأكد أولا بأنها تعمل بشكل جيد، وثانيا لكي نتيقن من أنه لا تعارض بينها وبين باقي أجزاء البرنامج.
القيام بكل هذا يدويا يصبح غير عملي مع ازدياد حجم التطبيق وتعقيده.
إذن الحل في الإختبارات البرمجية :)
ما هي الإختبارات البرمجية ؟
الإختبار البرمجي هو كود يتم كتابته لإختبار كود آخر :)
قد يقول قائل: ماذا ؟ هل تريد مني أن أكتب برنامجين عوض واحد ؟ أليس هذا مضيعة للوقت ؟
سيكون هذا التساؤل منطقيا ومقبولا خاصة من شخص مبتدئ لم يسبق له العمل على مشاريع كبيرة، أو لم يسبق له العمل مع فريق أو شركة تولي لهذا الموضوع الأهمية التي يستحقها.
ولكن ما يجب معرفته هو أن للإختبارات المؤتمتة إيجابيات كثيرة ومتنوعة، نذكر منها :
- توفير المال وعدم القلق من التحسينات في المستقبل: صحيح أنه على المدى القصير قد يبدو كتابة الإختبارات البرمجية أمرا مكلفا من حيث الوقت، وعندما نقول الوقت فإننا نشير إلى المال :) ولكن على المدى الطويل سندرك جيدا بأن ذلك استثمار يستحق ما وضع فيه من مال وسيوفر علينا لا حقا أضعاف ذلك. تخيل أنه قمت بتطور البرنامج وبعد فترة تود صيانته أو إجراء تحسينات عليه، من دون الإختبارات البرمجية سيكون من الوارد جدا أن التحسينات والإصلاحات الجديدة ستكون لها آثار سلبية على بعض الوظائف القديمة، بالخصوص إذا كان المطور ليس هو الذي قام بتطوير البرنامج في المرة الأولى أو أن البرنامج يعمل عليه فريق من المطورين.
- الإختبارات البرمجية بمثابة توثيق للكود: من ثمار الإختبارات البرمجية المكتوبة كذلك أنها توفر للمطورين توثيقا واضحا لمختلف وظائف البرنامج، والمدخلات التي تنتظرها (Inputs) وكذلك المخرجات المتوقعة منها (Outputs).
- تنظيم الكود أكثر: في أحيان كثيرة، عندما نحاول إنجاز الإختبارات البرمجية لوظيفة معينة تواجهنا عدة صعوبات في ذلك، إما لأن الشفرة المصدرية معقدة أو أنها متشابكة ومرتبطة بوظائف أخرى في البرنامج. هنا نقرر في العادة تقسيم كود الوظيفة إلى عدة جزاء صغيرة قابلة للإختبار بسهولة أكثر وغير متعارضة فيما بينها، وبالتالي كود أنظف وأفضل. بعض المطورين ذهبوا بعيدا في هذه النقطة حيث أنهم يكتبون الإختبارات قبل أن يكتبوا كود البرنامج :) وتعرف هذه الطريقة ب Test-driven development أو اختصارا TDD.
هذه كلها نقاط تستحق أن نجري اختباراتنا البرمجية من أجلها، وثمارها الواضحة ستبدو جلية عندما يكون المشروع جادا وفي تنامٍ مستمر. وتجدر الإشارة إلى أن جميع الشركات التقنية العملاقة في العالم (قوقل، فيسبوك، أمازون، تويتر…إلخ) تلزم المطورين لديها بكتابة وإجراء الإختبارات البرمجية - بجميع أنواعها - على أي مشروع أو برنامج يقومون بالإشتغال عليه.
إذن قد يكون الموضوع اختياريا بالنسبة لك كمطور حر أو في شركة صغيرة، ولكن لن يكون الأمر كذلك إذا كنت تريد اللعب على مستوى عالي وتنافسي.
على كل حال، كتابة أكواد الإختبار لا يجب أن يشكل لك مصدرا للقلق أو التوجس، لأن هناك عددا كبيرا من أطر العمل الخاصة فقط بهذا الموضوع وتوفر كافة الأدوات والواجهات البرمجية من أجل تسهيل العمل على المطورين.
ما هي أنواع الإختبارات البرمجية ؟
هناك عدة أصناف للإختبارات البرمجية الآلية، وتختلف بحسب الهدف المتوخى منها.
في المجمل، هناك ثلاثة أنواع أساسية :
1. الإختبارات الوحداتية (Unit Tests)
هذا النوع من الإختبارات هو الأكثر استخداما لأنه الأسهل، بحيث أنه يهتم فقط باختبار وظيفة معينة بمعزل عن أي تبعيات أو وحدات برمجية أخرى.
2. اختبارات التكامل (Integration Tests)
الغرض من هذا النوع من الإختبارات هو التأكد من أن وظائف أو وحدات معينة مرتبطة فيما بينها في البرنامج تعمل بشكل جيد وكما هو متوقع.
3. اختبارات الطرفين (End to End Tests)
تعرف كذلك باختبارات النظام لأن الهدف منها هو التأكد من أن النظام ككل يعمل كما يجب. في تطبيقات الويب يتم إجراء هذه الإختبارات بمحاكاة لبيئة المتصفح برمجيا عن طريق واجهات وحزم برمجية تعرف ب Headless Browsers، ومن أشهرها PhantomJs وPuppeteer.
أغلب الإختبارات البرمجية التي يجريها المطورون هي اختبارات من نوع Unit Tests لأنها الأسهل ولا تتطلب كتابة كثير من الكود، تليها الإختبارات التكاملية ثم اختبارات النظام (End to End). هذه الأخيرة هي الأكثر تكلفة لأنها تتطلب وقتا ومجهودا كبيرين في كتابتها وإجرائها.
المطورون في شركة Google يرون بأنه سيكون من الجيد إذا تم الحفاظ على هذه معدلات كهذه:
- 70% اختبارات Unit Tests.
- 20% اختبارات تكاملية.
- 10% اختبارات E2E.
وينصحون كذلك بالتقليل قدر الإمكان من E2E Tests لحساب Unit Tests وIntegration Tests. ولكن لا يجب اعتبار هذه التوليفة حقيقة مطلقة يجب الإلتزام بها حرفيا، لأن المسألة تتعلق قبل كل شيء بطبيعة المشروع.
يمكن اختصار كل ما قلناه في هذه الصورة التي تعرف بهرم الإختبار (Testing Pyramid) :
في الختام
أتمنى لا تكون الطبيعة النظرية لهذا المقال قد أشعرتكم بالملل :)
في الحقيقة أنا كذلك لا أحب الكلام النظري الطويل، ولكن لم يكن بيدي خيار آخر لأنه لم يسبق لنا التطرق لموضوع Testing في مدونة توتومينا من قبل، وأظن أن موضوع واحد من هذا النوع سيكون أساسا جيدا نبني عليه ما هو قادم من مواضيع ودروس تطبيقية.
إلى ذلك الحين، سأكون سعيدا إذا شاركتم معي تجاربكم مع الإختبارات البرمجية الآلية.. هل تقومون بها ؟ وهل ترون بأنها مسألة ضرورية تستحق استثمار جهودكم وأوقاتكم فيها ؟