AICODEAgentic Programming · 67723 · 2026-7

Week 5 · video 4 of 8 · transcript

From Stories to Tests

ترجمة آلية لم يراجعها إنسان.AI translation, not reviewed by a person.

0:01

تصف المواصفات ما يجب أن يفعله البرنامج. سنستخدم تطبيق مهام صغيرًا لنحوّل أحد متطلباته إلى اختبار. يُشغَّل هذا الاختبار مع كل تغيير، فلا يحتاج السلوك الذي يغطيه إلى فحص يدوي آخر في كل مرة. سنكتب المتطلَّب على شكل قصة مستخدم، ونقسّمه إلى given و when و then، ثم نكتبه في pytest. بعد ذلك سنختبر ميزتين معًا، لأن كل ميزة قد تجتاز اختباراتها الخاصة بينما يفشل الجمع بينهما.

0:30

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

0:47

تلك المراجعة اليدوية حدثت مرة واحدة. وهي تخبركم بما كان صحيحًا في تلك اللحظة فقط. والتغيير التالي يحتاج إلى فحص آخر لهذه المتطلبات.

0:55

انظروا الآن إلى البنود الثلاثة الأولى. كل بند منها يذكر شيئًا يفعله البرنامج، ولذلك يستطيع برنامجٌ أن يتحقّق منه. ويمكن تشغيل هذا الفحص مع كل تغيير، لا مرة واحدة فقط.

1:07

هذه قدرة نريدها في تطبيق المهام لدينا. يجب أن يتمكّن المستخدم من حفظ قائمة المهام وتحميلها مرة أخرى لاحقًا، حتى لا تضيع عند إغلاق التطبيق. في فرق البرمجة، يُسمّى المتطلَّب المكتوب من وجهة نظر المستخدم، مثل هذا، قصة مستخدم. هنا نعبّر عن القصة بجملة واحدة تقول ما يفعله المستخدم وما يجب أن يحدث.

1:29

تذكر القصة من يفعل شيئًا، وماذا يفعل، وما يجب أن يحدث بعد ذلك. وهي مكتوبة بكلماتكم أنتم، الكلمات التي تصفون بها البرنامج لصديق.

1:40

القصة مكتوبة من خارج البرنامج. فهي لا تذكر أي دالة أو صيغة ملف أو إطار عمل، لذلك يمكن أن يتغيّر التنفيذ بينما يبقى المتطلَّب كما هو. قد تُحفظ القائمة في ملف أو في قاعدة بيانات، وفي الحالتين تبقى القصة كما هي. لكن الاختبار الذي نكتبه منها لا بدّ أن يحدّد أمرين: طريقة محدَّدة لاستدعاء البرنامج، وبيانات محدَّدة يجرّبه بها. هذه الاختيارات تخصّ الاختبار، لا القصة.

2:06

لتحويل هذه القصة إلى اختبار، نقسمها إلى ثلاثة أجزاء. الجزء الأول يهيّئ الوضع الذي تفترضه القصة، وهو هنا قائمة مهام فيها ثلاثة عناصر: Buy milk و Call mom و Pay rent.

2:19

الجزء الثاني ينفّذ الإجراء. نحفظ القائمة، ثم نحمّلها في نسخة جديدة من التطبيق، كما ستُحمَّل بعد إغلاق التطبيق.

2:28

الجزء الثالث يتحقّق من النتيجة المتوقَّعة. القائمة المحمَّلة هي القائمة نفسها: العناصر نفسها، بالترتيب نفسه، دون أي عنصر زائد أو ناقص. لكلمة «نفسها» في القصة دور حقيقي، وعلى الـ assertion أن يتحقّق منها. قد ينفّذ الاختبار عدة إجراءات، ويتحقّق من عدة نتائج حين يتطلّب السيناريو ذلك. ويبقى مركَّزًا لأنه يتحقّق من سلوك واحد، فيشير الفشل إلى شيء واحد تبحثون فيه.

2:55

تُسمّى هذه الأجزاء الثلاثة given و when و then، بهذا الترتيب. وهي من التطوير الموجَّه بالسلوك (BDD). تشمل هذه الممارسة أدوات صيغتها قريبة من الإنجليزية، وكود ربط يجعل هذه الخطوات قابلة للتشغيل. أما هنا فنستخدم البنية الثلاثية نفسها مباشرة في اختبار عادي.

3:15

هذه هي الأجزاء الثلاثة نفسها مكتوبةً بالكود. المثال بلغة Python، ويشغّله pytest. السطر الأول يستدعي list_with، وهي دالة مساعدة صغيرة كُتبت لهذه الاختبارات. وهي تبني قائمة من العناصر الثلاثة، وكلها ما زالت مفتوحة. السطر الثاني يحفظ القائمة ثم يحمّل النص المحفوظ من جديد. الدالة load تبني قائمة جديدة من هذا النص وحده، وهذا ما تفعله نسخة جديدة من التطبيق. يستدعي الاختبار save و load مباشرة، كدوال عادية، دون متصفح. فهو يتحقّق من كود الحفظ والتحميل نفسه. ولا يُثبت أن زر Save في الصفحة يستدعي هذا الكود فعلًا، وهذا ما يتحقّق منه اختبار المتصفح. السطر الأخير يقارن القائمة المحمَّلة بالأصلية، عنصرًا عنصرًا. فهو يتحقّق من كل عنصر، ومن كل ما سُجّل عن كل عنصر، ومن ترتيب العناصر. والترتيب هنا جزء من المتطلَّب، لأن بندًا آخر ينصّ على إضافة العناصر الجديدة في أسفل القائمة، ويجب ألا يغيّر التحميل ترتيبها.

4:09

اسم الاختبار يقول إن القائمة المحفوظة تُحمَّل كما هي، وهو قريب جدًا من القصة. وهذا يسهّل ربط اختبار فاشل بالسلوك الذي وعدتم به. أما الاسم الذي يتحدث عن التحويل إلى JSON والعودة منه فيصف التنفيذ، لكنه لا يوضّح بالقدر نفسه ما يجب أن يستعيده المستخدم.

4:28

هكذا يبدو الفشل. يقول التقرير إن في القائمة الأصلية عنصرًا زائدًا عن المحمَّلة، هو Pay rent. العنصر الأخير ضاع في الطريق، وهذه نتيجة خاطئة ملموسة يمكن البحث فيها، بدءًا من الكود الذي يقرأ القائمة المحفوظة من جديد. ويذكر التقرير اسم الاختبار أيضًا، فتربطون العنصر الناقص بالمتطلَّب: أن تعود القائمة نفسها.

4:51

لنعد إلى تطبيق المهام. إلى جانب الحفظ والتحميل، فيه ميزة أخرى. يمكنكم إكمال عنصر بالنقر على مربّع الاختيار بجانبه، وهذا يضع على العنصر علامة «مكتمل». عامل التصفية Active يستخدم هذه العلامة. فهو يعرض فقط العناصر التي لم تكتمل بعد. لإكمال العنصر اختبار خاص به، وهذا الاختبار ينجح. واختبار الحفظ والتحميل الذي كتبناه للتو ينجح أيضًا. لاحظوا أن اختبار الحفظ والتحميل استخدم قائمة لا عنصر مكتمل فيها. كل عناصرها كانت ما زالت مفتوحة.

5:20

لنستخدم الآن الميزتين معًا، كما يفعل المستخدم. أولًا، ينقر المستخدم على مربّع الاختيار بجانب Buy milk، فيصبح Buy milk مكتملًا. ثم يحفظ المستخدم القائمة. لاحقًا، يفتح المستخدم التطبيق من جديد ويحمّل القائمة. أخيرًا، يختار المستخدم عامل التصفية Active ليرى ما بقي عليه إنجازه.

5:40

كان Buy milk مكتملًا قبل حفظ القائمة. لذلك يجب أن يعرض عامل التصفية Active العنصر Call mom وحده. لكن التطبيق يعرض Buy milk و Call mom معًا. الملف المحفوظ يفسّر السبب. فهو يسجّل لكل عنصر عنوانه، ولا شيء غيره. ولا يسجّل إن كان العنصر مكتملًا. لذلك عند تحميل القائمة، يعود كل عنصر على أنه غير مكتمل، ويظهر Buy milk من جديد كمهمة لم تكتمل بعد.

6:07

اكتمال العنصر أو عدمه جزء من حالة (state) تطبيق المهام، التي لا تقتصر على قائمة العناوين. في الكود، يحتفظ كل عنصر بهذه العلامة في حقل اسمه done. وعندما يحفظ المستخدم، على التطبيق أن يحفظ الحقل done أيضًا. من الطرق الجيدة لاكتشاف مشكلات كهذه أن تتتبّعوا جزءًا من الحالة عبر التطبيق. النقر على مربّع الاختيار يضبط الحقل done، وعامل التصفية Active يقرؤه ليقرّر ما يعرضه. وبين هذين، على الحفظ والتحميل أن ينقلاه، لكن الحفظ هنا يُسقطه. لم يجرّب أيٌّ من الاختبارين هذا المسار، لأن اختبار الحفظ والتحميل لم يحفظ أبدًا عنصرًا مكتملًا.

6:44

هذا اختبار للجمع بين الميزتين، بالشكل نفسه: given، و when و then. يبدأ بعنصرين مفتوحين، Buy milk و Call mom. ثم يُكمل Buy milk، وهذا ما يفعله النقر على مربّع الاختيار. ثم يحفظ القائمة ويحمّلها من جديد في قائمة جديدة، كما يحدث عند إعادة فتح التطبيق. السطر الأخير يتحقّق مما سيعرضه عامل التصفية Active. فهو يستدعي visible_items، الدالة التي تقرّر أيّ العناصر يعرضها كل عامل تصفية. ونتوقّع Call mom وحده. لهذا الاختبار عدة خطوات، لكنه يتحقّق من نتيجة واحدة. وعند تشغيله على التطبيق الحالي يفشل، لأن Buy milk يعود غير مكتمل.

7:22

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

7:41

عند كتابة المواصفات، ابحثوا عن بنود تستطيعون وصف نتيجتها بدقة. فكل بند منها يصف سلوكًا قابلًا للاختبار: يهيّئ الاختبار وضعًا، ثم يقارن النتيجة بما هو متوقَّع.

7:53

الذوق أمر مختلف. «نظيف» و«مريح للعين» و«سريع» أحكام على الانطباع الذي يتركه التطبيق، لا حقائق عمّا يفعله البرنامج. يمكن لاختبار أن يحسم إن كان التطبيق يعرض العناصر غير المكتملة وحدها. لكن لا يحسم أي اختبار إن كانت القائمة تبدو نظيفة. هذه الأحكام تحتاج إلى مراجعة تجربة الاستخدام نفسها، حتى عندما يمكن فحص بعض الخصائص الداعمة تلقائيًا. ومع ذلك، قد يقود الحكم إلى هدف قابل للقياس. عبارة «يبدو سريعًا» قد تصبح قاعدة: أن يظهر العنصر الجديد خلال عُشر ثانية. يمكن لاختبارٍ فحص هذا الرقم، لكن ما زال على أحدهم أن يستخدم التطبيق ليحكم إن كان يبدو سريعًا.

8:29

أبقوا في المواصفات أيضًا هذه المتطلبات المبنية على الحكم. فهي تخبركم بما يجب مراجعته كلما تغيّرت الواجهة. التمييز بين النوعين أثناء الكتابة يساعدكم على التخطيط للفحوصات الآلية وللمراجعة اليدوية معًا.

8:43

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

8:57

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

9:07

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

9:20 of video · 1,327 words · 26 slides← Back to the video