هذه المقالة مقتبسة من فصل من كتاب الدليل الوظيفي الكامل للبرمجيات. يكتبه مؤلفه، جون سونميز، وينشر بعض الفصول على موقعه على الإنترنت.
لدي علاقة مختلطة للغاية مع التطوير المبني على الاختبار (TDD) واختبار الوحدة، حيث انتقلت من الحب إلى الكراهية والعودة مرة أخرى. لقد كنت من أشد المعجبين بها، وفي الوقت نفسه كنت متشككًا بشأن استخدام هذه "أفضل الممارسات" وغيرها. ويستند السبب وراء موقفي إلى حقيقة مفادها أن مشكلة خطيرة ظهرت في عمليات تطوير البرمجيات: حيث يستخدم المطورون، وأحيانا المديرون، أدوات ومنهجيات معينة فقط لأنها تنتمي إلى "أفضل الممارسات". السبب الحقيقي لاستخدامها لا يزال غير واضح. في أحد الأيام، بدأت العمل في مشروع معين، وأثناء هذه العملية تم إبلاغي بأننا سنقوم بتعديل التعليمات البرمجية التي يغطيها عدد كبير من اختبارات الوحدات. ليس مزحة، كان هناك حوالي 3000 منهم، وهذه عادة علامة جيدة، إشارة إلى أن المطورين يستخدمون منهجيات متقدمة. غالبًا ما يتم تنظيم الكود باستخدام هذا النهج ويعتمد على بنية مدروسة جيدًا. باختصار، وجود الاختبارات جعلني سعيدًا، ولو فقط لأنه يعني تسهيل عملي كمرشد للمبرمجين. نظرًا لأن لدينا بالفعل اختبارات الوحدة، كل ما كان علي فعله هو الاتصال بفريق التطوير لدعمهم والبدء في كتابة التعليمات البرمجية الخاصة بنا. لقد فتحت IDE (بيئة التطوير المتكاملة) وقمت بتحميل المشروع.
لقد كان مشروعًا كبيرًا! لقد وجدت مجلدًا بعنوان "اختبارات الوحدة". اعتقدت "رائع". - دعونا نطلقه ونرى ما سيحدث. استغرق الأمر بضع دقائق فقط، ولدهشتي، نجحت جميع الاختبارات، وكان كل شيء باللون الأخضر ( "الأخضر" هو نتيجة إيجابية للاختبار. إشارات إلى أن الكود يعمل كما هو متوقع. يشير اللون الأحمر إلى "فشل" أو فشل، ثم هناك حالة لا يعمل فيها الكود بشكل صحيح - ملاحظة المترجم ). لقد نجحوا جميعا في الاختبار. في تلك اللحظة، استيقظ المتشكك بداخلي. كيف ذلك، ثلاثة آلاف وحدة اختبار، وأجروها كلها مرة واحدة - وأعطوا نتيجة إيجابية؟ في ممارستي الطويلة، لم أتمكن من تذكر الوقت الذي بدأت فيه العمل في مشروع دون اختبار وحدة سلبي واحد في الكود. ما يجب القيام به؟ تحقق يدويا! اختار ChY اختبارًا عشوائيًا واحدًا، لم يكن الأكثر كشفًا، ولكن كان من الواضح على الفور ما كان يفحصه. لكن أثناء العمل فيه لاحظت شيئًا سخيفًا: الاختبار لم يحتوي على أي مقارنات مع النتيجة المتوقعة (التأكيدات)! أي أنه في الواقع لم يتم التحقق من أي شيء على الإطلاق ! كانت هناك خطوات معينة في الاختبار، تم تنفيذها، ولكن في نهاية الاختبار، حيث يجب عليه مقارنة النتائج الفعلية والمتوقعة، لم يكن هناك أي فحص. "الاختبار" لم يختبر أي شيء. فتحت اختبارا آخر. والأفضل من ذلك: تم التعليق على عامل المقارنة مع النتيجة. ببراعة! هذه طريقة رائعة لإجراء اجتياز الاختبار، ما عليك سوى التعليق على الكود الذي يتسبب في فشله. لقد راجعت اختبارًا آخر، ثم آخر... لم يفحص أي منهم أي شيء. ثلاثة آلاف اختبار، وكلها عديمة الفائدة تمامًا. هناك فرق كبير بين كتابة اختبارات الوحدة وفهم اختبار الوحدة والتطوير القائم على الاختبار (TDD).
الفكرة الأساسية لاختبار الوحدة هي كتابة اختبارات تختبر أصغر "وحدة" من التعليمات البرمجية. عادةً ما تتم كتابة اختبارات الوحدة بنفس لغة البرمجة مثل الكود المصدري للتطبيق. يتم إنشاؤها مباشرة لاختبار هذا الرمز. أي أن اختبارات الوحدة هي عبارة عن تعليمات برمجية تتحقق من صحة التعليمات البرمجية الأخرى. أستخدم كلمة "اختبار" بحرية تامة في السياق، لأن اختبارات الوحدة ليست اختبارات إلى حد ما. إنهم لا يواجهون أي شيء. ما أعنيه هو أنه عند إجراء اختبار الوحدة، فإنك لا تجد عادةً أن بعض التعليمات البرمجية لا تعمل. تكتشف ذلك أثناء كتابة الاختبار، لأنك ستقوم بتغيير الكود حتى يتحول لون الاختبار إلى اللون الأخضر. نعم، قد يتغير الرمز لاحقًا ومن ثم قد يفشل الاختبار. وبهذا المعنى، فإن اختبار الوحدة هو اختبار الانحدار. لا يعد اختبار الوحدة بمثابة اختبار عادي حيث يكون لديك بعض الخطوات التي ستتبعها وترى ما إذا كان البرنامج يعمل بشكل صحيح أم لا. أثناء عملية كتابة اختبار الوحدة، تكتشف ما إذا كان الكود يقوم بما يفترض أن يفعله أم لا، وسوف تقوم بتغيير الكود حتى ينجح الاختبار.
لماذا لا تكتب اختبار الوحدة وتتحقق من نجاحه؟ إذا فكرت في الأمر بهذه الطريقة، فإن اختبارات الوحدة تتحول إلى نوع من المتطلبات المطلقة لوحدات تعليمات برمجية معينة عند مستوى منخفض جدًا. يمكنك التفكير في اختبار الوحدة باعتباره مواصفات مطلقة . يحدد اختبار الوحدة أنه في ظل هذه الظروف، مع هذه المجموعة المحددة من المدخلات، هناك مخرج يجب أن تحصل عليه من وحدة التعليمات البرمجية هذه. يحدد اختبار الوحدة الحقيقي أصغر وحدة متماسكة من التعليمات البرمجية، والتي تعتبر فئة في معظم لغات البرمجة - على الأقل تلك الموجهة للكائنات.
غالبًا ما يتم الخلط بين اختبار الوحدة واختبار التكامل. تختبر بعض "اختبارات الوحدة" أكثر من فئة واحدة أو تختبر وحدات كبيرة من التعليمات البرمجية. يدعي الكثير من المطورين أنهم يكتبون اختبارات الوحدة بينما في الواقع يكتبون اختبارات Whitebox منخفضة المستوى. لا تجادل مع هؤلاء الرجال. فقط اعلم أنهم يكتبون بالفعل اختبارات التكامل، واختبارات الوحدة الحقيقية تختبر أصغر وحدة من التعليمات البرمجية بمعزل عن الأجزاء الأخرى. الشيء الآخر الذي يُطلق عليه غالبًا اختبار الوحدة هو اختبارات الوحدة دون التحقق من القيمة المتوقعة. بمعنى آخر، اختبارات الوحدة التي لا تختبر أي شيء فعليًا. يجب أن يتضمن أي اختبار، سواء كان موحدًا أم لا، نوعًا ما من التحقق - ونطلق عليه التحقق من النتيجة الفعلية مقابل النتيجة المتوقعة. وهذه التسوية هي التي تحدد ما إذا كان الاختبار سينجح أم يفشل. الاختبار الذي ينجح دائمًا لا فائدة منه. الاختبار الذي يفشل دائمًا لا فائدة منه.
هناك سببان رئيسيان لإجراء اختبار الوحدة. الأول هو تحسين تصميم التعليمات البرمجية. هل تتذكر كيف قلت أن اختبار الوحدة ليس اختبارًا حقيقيًا؟ عندما تكتب اختبارات الوحدة المناسبة، فإنك تجبر نفسك على عزل أصغر وحدة من التعليمات البرمجية. ستقودك هذه المحاولات إلى اكتشاف مشاكل في بنية الكود نفسه. قد تجد صعوبة بالغة في عزل فئة الاختبار وعدم تضمين تبعياتها، وهذا قد يجعلك تدرك أن الكود الخاص بك مقترن بإحكام شديد. قد تجد أن الوظيفة الأساسية التي تحاول اختبارها تشمل وحدات متعددة، مما يقودك إلى الاعتقاد بأن التعليمات البرمجية الخاصة بك ليست متماسكة بما فيه الكفاية. عندما تجلس لكتابة اختبار الوحدة، قد تكتشف فجأة (وصدقني، يحدث ذلك!) أنه ليس لديك أي فكرة عما يفترض أن يفعله الكود. وبناء على ذلك، لا توجد طريقة يمكنك من خلالها كتابة اختبار وحدة لذلك. وبالطبع، قد تجد خطأً حقيقيًا في تنفيذ الكود، نظرًا لأن اختبار الوحدة يجبرك على التفكير خارج الصندوق واختبار مجموعات مختلفة من المدخلات التي ربما لم تفكر فيها.
إذا كنت تلتزم بشكل صارم بقاعدة "اختبار أصغر وحدة من التعليمات البرمجية بمعزل عن الوحدات الأخرى" عند إنشاء اختبارات الوحدة، فلا بد أن تجد جميع أنواع المشكلات المتعلقة بهذا الرمز وتصميم تلك الوحدات. في دورة حياة تطوير البرمجيات، يعد اختبار الوحدة بمثابة نشاط تقييم أكثر من كونه نشاط اختبار. الهدف الرئيسي الثاني لاختبار الوحدة هو إنشاء مجموعة تلقائية من اختبارات الانحدار التي يمكن أن تكون بمثابة مواصفات منخفضة المستوى لسلوك البرنامج. ماذا يعني ذلك؟ عندما تعجن العجينة لا تكسرها. من وجهة النظر هذه، اختبارات الوحدة هي اختبارات، وبشكل أكثر تحديدًا اختبارات الانحدار. ومع ذلك، فإن الغرض من اختبار الوحدة ليس مجرد بناء اختبارات الانحدار. من الناحية العملية، نادرًا ما تكتشف اختبارات الوحدة الانحدارات، نظرًا لأن التغيير في وحدة التعليمات البرمجية التي تختبرها يحتوي دائمًا على تغييرات في اختبار الوحدة نفسها. يعد اختبار الانحدار أكثر فعالية على المستوى الأعلى، عندما يتم اختبار الكود على أنه "صندوق أسود"، لأنه في هذا المستوى يمكن تغيير البنية الداخلية للكود، بينما من المتوقع أن يظل السلوك الخارجي كما هو. تقوم اختبارات الوحدة بدورها بفحص البنية الداخلية بحيث لا تفشل اختبارات الوحدة عندما تتغير تلك البنية. لقد أصبحت غير صالحة للاستعمال وتحتاج الآن إلى التغيير أو التخلص منها أو إعادة كتابتها. أنت تعرف الآن المزيد عن الغرض الحقيقي من اختبار الوحدة أكثر من العديد من مطوري البرامج المخضرمين.
في عملية تطوير البرمجيات، المواصفات الجيدة تستحق وزنها ذهباً. نهج TDD هو أنه قبل كتابة أي كود، عليك أولاً كتابة اختبار سيكون بمثابة مواصفات، أي تحديد ما يجب أن يفعله الكود. يعد هذا مفهومًا قويًا للغاية لتطوير البرمجيات، ولكن غالبًا ما يتم إساءة استخدامه. عادةً ما يعني التطوير القائم على الاختبار استخدام اختبارات الوحدة لتوجيه إنشاء رمز التطبيق. ولكن في الواقع، يمكن تطبيق هذا النهج على أي مستوى. ومع ذلك، في هذه المقالة سنفترض أننا نستخدم اختبار الوحدة لتطبيقنا. يقلب نهج TDD كل شيء رأسًا على عقب، فبدلاً من كتابة التعليمات البرمجية أولاً ثم كتابة اختبارات الوحدة لاختبار هذا الرمز، تكتب اختبار الوحدة أولاً ثم تكتب التعليمات البرمجية لجعل هذا الاختبار أخضر اللون. وبهذه الطريقة، فإن اختبار الوحدة "يقود" إلى تطوير التعليمات البرمجية. وتتكرر هذه العملية مرارا وتكرارا. تكتب اختبارًا آخر يحدد المزيد من الوظائف لما يجب أن يفعله الكود. تقوم بعد ذلك بكتابة التعليمات البرمجية وتعديلها للتأكد من اكتمال الاختبار بنجاح. بمجرد حصولك على نتيجة خضراء، تبدأ في إعادة بناء الكود، أي إعادة هيكلته أو تنظيفه لجعله أكثر إيجازًا. غالبًا ما تسمى سلسلة العمليات هذه "إعادة البناء بالأحمر والأخضر" لأنه أولاً يفشل اختبار الوحدة (الأحمر)، ثم تتم كتابة الكود للتكيف مع الاختبار، والتأكد من نجاحه (الأخضر)، وأخيرًا يتم تحسين الكود ( إعادة بناء التعليمات البرمجية). .
يمكن استخدام التطوير المبني على الاختبار (TDD)، مثل اختبار الوحدة، بشكل غير صحيح. من السهل جدًا تسمية ما تفعله بـ "TDD" وحتى اتباع الممارسة دون فهم سبب قيامك بذلك بهذه الطريقة. القيمة الأكبر لـ TDD هي إجراء الاختبارات لإنتاج مواصفات الجودة. TDD هي في الأساس ممارسة كتابة المواصفات الدقيقة التي يمكن التحقق منها تلقائيًا قبل كتابة الترميز. الاختبارات هي أفضل المواصفات لأنها لا تكذب. لن يخبروك بعد أسبوعين من العذاب برمز "هذا ليس ما أقصده على الإطلاق". الاختبارات، عندما تتم كتابتها بشكل صحيح، إما تنجح أو تفشل. تشير الاختبارات بوضوح إلى ما يجب أن يحدث في ظل ظروف معينة. وبالتالي، فإن هدف TDD هو منحنا فهمًا كاملاً لما نحتاج إلى تنفيذه قبل أن نبدأ في تنفيذه. إذا كنت تبدأ باستخدام TDD ولم تتمكن من معرفة ما الذي من المفترض أن يختبره الاختبار، فأنت بحاجة إلى طرح المزيد من الأسئلة. هناك دور مهم آخر لـ TDD وهو الحفاظ على التعليمات البرمجية وتحسينها. صيانة الكود مكلفة. كثيرًا ما أمزح قائلًا إن أفضل مبرمج هو من يكتب أقصر كود يحل بعض المشكلات. أو حتى من يثبت أن هذه المشكلة لا تحتاج إلى حل، وبالتالي إزالة الكود بالكامل، حيث أن هذا المبرمج هو الذي وجد الطريقة الصحيحة لتقليل عدد الأخطاء وتقليل تكلفة صيانة التطبيق. باستخدام TDD، يمكنك التأكد تمامًا من أنك لا تكتب أي تعليمات برمجية غير ضرورية، حيث أنك ستكتب التعليمات البرمجية فقط لاجتياز الاختبارات. هناك مبدأ لتطوير البرمجيات يسمى YAGNI (لن تحتاج إليه). TDD يمنع YAGNI.
من الصعب فهم معنى TDD من وجهة نظر أكاديمية بحتة. لذلك دعونا نلقي نظرة على مثال لجلسة TDD. تخيل أنك تجلس على مكتبك وترسم بسرعة ما تعتقد أنه سيكون تصميمًا عالي المستوى لميزة تسمح للمستخدم بتسجيل الدخول إلى أحد التطبيقات وتغيير كلمة المرور الخاصة به إذا نسيها. لقد قررت أنك ستبدأ بالتنفيذ الأول لوظيفة تسجيل الدخول، وإنشاء فئة ستتعامل مع كل المنطق الخاص بعملية تسجيل الدخول. يمكنك فتح المحرر المفضل لديك وإنشاء اختبار وحدة يسمى "تسجيل الدخول الفارغ يمنع المستخدم من تسجيل الدخول". تكتب رمز اختبار الوحدة الذي يقوم أولاً بإنشاء مثيل لفئة تسجيل الدخول (التي لم تقم بإنشائها بعد). تقوم بعد ذلك بكتابة رمز لاستدعاء طريقة في فئة تسجيل الدخول تقوم بتمرير اسم مستخدم وكلمة مرور فارغين. أخيرًا، تكتب شيكًا مقابل النتيجة المتوقعة، وتتحقق من أن المستخدم الذي لديه معلومات تسجيل دخول فارغة لم يتم تسجيل دخوله فعليًا. أنت تحاول إجراء اختبار، لكنه لا يتم تجميعه حتى لأنه ليس لديك فئة تسجيل الدخول. يمكنك إصلاح هذا الموقف وإنشاء فئة تسجيل الدخول مع طريقة في تلك الفئة لتسجيل الدخول وأخرى للتحقق من حالة المستخدم لمعرفة ما إذا كان قد تم تسجيل الدخول أم لا. حتى الآن لم تقم بتنفيذ وظيفة هذه الفئة والطريقة التي نحتاجها. يمكنك إجراء الاختبار في هذه المرحلة. الآن يجمع، لكنه فشل على الفور.
يمكنك الآن العودة إلى الكود وتنفيذ الوظيفة لاجتياز الاختبار. في حالتنا، هذا يعني أننا يجب أن نحصل على النتيجة: "لم يتم تسجيل دخول المستخدم". قمت بإجراء الاختبار مرة أخرى والآن نجح. دعنا ننتقل إلى الاختبار التالي. لنتخيل الآن أنك بحاجة إلى كتابة اختبار يسمى "يتم تسجيل دخول المستخدم إذا أدخل اسم مستخدم وكلمة مرور صالحين". تكتب اختبار وحدة يقوم بإنشاء مثيل لفئة تسجيل الدخول ويحاول تسجيل الدخول باستخدام اسم المستخدم وكلمة المرور. في اختبار الوحدة، تكتب عبارة مفادها أن فئة تسجيل الدخول يجب أن تجيب بنعم على سؤال ما إذا كان المستخدم قد قام بتسجيل الدخول أم لا. قمت بتشغيل هذا الاختبار الجديد وبالطبع فشل لأن فئة تسجيل الدخول الخاصة بك تُرجع دائمًا أن المستخدم لم يقوم بتسجيل الدخول. يمكنك العودة إلى فئة تسجيل الدخول الخاصة بك وتنفيذ بعض التعليمات البرمجية للتحقق من قيام المستخدم بتسجيل الدخول. في هذه الحالة، سيكون عليك معرفة كيفية عزل هذه الوحدة. في الوقت الحالي، أسهل طريقة للقيام بذلك هي كتابة اسم المستخدم وكلمة المرور اللذين استخدمتهما في الاختبار، وإذا كانا متطابقين، قم بإرجاع النتيجة "تم تسجيل دخول المستخدم". يمكنك إجراء هذا التغيير، وإجراء كلا الاختبارين، وينجح كلاهما. دعنا ننتقل إلى الخطوة الأخيرة: تنظر إلى الكود الذي تم إنشاؤه، وتبحث عن طريقة لإعادة تنظيمه وتبسيطه. لذا فإن خوارزمية TDD هي:
هذا كل ما أردت إخبارك به عن اختبار الوحدة وTDD في هذه المرحلة. في الواقع، هناك العديد من الصعوبات المرتبطة بمحاولة عزل وحدات التعليمات البرمجية، حيث يمكن أن تكون التعليمات البرمجية معقدة للغاية ومربكة. يوجد عدد قليل جدًا من الفصول في عزلة تامة. بدلاً من ذلك، لديهم تبعيات، وهذه التبعيات لها تبعيات، وهكذا. للتعامل مع مثل هذه المواقف، يستخدم خبير TDD نماذج وهمية، والتي تساعد في عزل الفئات الفردية عن طريق استبدال الكائنات في الوحدات التابعة. هذه المقالة مجرد نظرة عامة ومقدمة مبسطة إلى حد ما لاختبار الوحدة وTDD، ولن نخوض في التفاصيل حول الوحدات الوهمية وتقنيات TDD الأخرى. تتمثل الفكرة في إعطائك المفاهيم والمبادئ الأساسية لـ TDD واختبار الوحدة التي نأمل أن تكون لديك الآن. الأصلي - https://simpleprogrammer.com/2017/01/30/tdd-unit-testing/
معجم قصير للمبتدئين
اختبار الوحدة أو اختبار الوحدة هو عملية في البرمجة تسمح لك بالتحقق من الوحدات الفردية للكود المصدري للبرنامج للتأكد من صحتها. الفكرة هي كتابة اختبارات لكل وظيفة أو طريقة غير تافهة. اختبار الانحدار هو اسم عام لجميع أنواع اختبارات البرامج التي تهدف إلى اكتشاف الأخطاء في المناطق التي تم اختبارها بالفعل من التعليمات البرمجية المصدر. مثل هذه الأخطاء - عندما يتوقف شيء يجب أن يستمر في العمل عن العمل بعد إجراء تغييرات على البرنامج - تسمى أخطاء الانحدار. النتيجة الحمراء، فشل - فشل الاختبار. الفرق بين النتيجة المتوقعة والفعلية. النتيجة الخضراء، النجاح - نتيجة اختبار إيجابية. والنتيجة الفعلية لا تختلف عما تم الحصول عليه. ***ما هو اختبار الوحدة؟
ما يسمى أحيانا اختبار الوحدة؟
قيمة اختبار الوحدة
لماذا أنا متحمس لاختبار الوحدة؟ لماذا من المضر أن نطلق على الاختبار المعمم، والذي يتضمن اختبار ليس أصغر كتلة معزولة عن التعليمات البرمجية الأخرى، ولكن جزء أكبر من التعليمات البرمجية، "اختبار الوحدة"؟ ما المشكلة إذا كانت بعض اختباراتي لا تقارن بين النتائج المستلمة والمتوقعة؟ على الأقل ينفذون الكود. سأحاول أن أشرح.ما هو التطوير المبني على الاختبار (TDD)؟
ما هو هدف TDD؟
سير عمل التطوير النموذجي القائم على الاختبار (TDD).
- تم إنشاء اختبار.
- لقد كتبنا رمزًا لهذا الاختبار.
- إعادة صياغة الكود.
GO TO FULL VERSION