تعلم كيف تحوّل كل مطالبة ميزة إلى 5–10 سيناريوهات قبول واضحة تغطي المسارات السعيدة وحالات الحافة بدون مجموعات اختبار منتفخة.

مطالبات النمط الحواري تبدو واضحة لأنها تُقرأ كحوار. لكنها غالبًا تضغط خيارات وقواعد واستثناءات داخل جمل ودية قليلة. الفجوات لا تظهر إلا عندما يستخدم شخص ما الميزة فعليًا.
معظم المطالبات تعتمد بصمت على افتراضات: من المسموح له القيام بالفعل، ما الذي يُحسب "نجاحًا" (محفوظ، مُرسل، منشور، مُدفوع)، ماذا يحدث عندما تكون البيانات مفقودة، وما الذي يجب أن يراه المستخدم عند فشل شيء ما. كما تخفي معايير غامضة مثل معنى "سريع بما فيه الكفاية" أو "آمن بما فيه الكفاية".
عادةً ما يظهر الغموض متأخرًا كأخطاء وإعادة عمل. يبني المطوّر ما يعتقد أن المطالبة تعنيه، ويوافق المراجع لأن الأمر يبدو صحيحًا، ثم يواجه المستخدمون الحالات الغريبة: إرساليات مكررة، مناطق زمنية، بيانات جزئية، أو عدم تطابق في الأذونات. إصلاح هذه الأشياء لاحقًا يكلف أكثر لأنه غالبًا يمس الكود، نصوص واجهة المستخدم، وأحيانًا نموذج البيانات.
الجودة لا تتطلب مجموعات اختبار ضخمة. الجودة هي أن تثق بالميزة في الاستخدام العادي وتحت ضغط متوقع. مجموعة صغيرة من السيناريوهات المُختارة جيدًا تمنحك تلك الثقة بدون مئات الاختبارات.
تعريف عملي للجودة للميزات المبنية من مطالبات:
هذا هو الهدف من تحويل المطالبات إلى سيناريوهات قبول: خذ طلبًا غامضًا وحوّله إلى 5–10 فحوصات تُظهر القواعد المخفية مبكرًا. لست تحاول اختبار كل شيء. أنت تحاول الإمساك بالأخطاء التي تحدث فعليًا.
إذا بنيت من مطالبة سريعة في أداة برمجة بالمزاج مثل Koder.ai، قد يبدو الناتج كاملًا بينما يتخطى قواعد الحافة. مجموعة سيناريوهات مضبوطة تُجبر على تسمية تلك القواعد بينما التغييرات لا تزال رخيصة.
سيناريو اختبار القبول هو وصف قصير وبسيط لعمل مستخدم والنتيجة التي يجب أن يراها.
ابقَ على السطح: ما الذي يستطيع المستخدم فعله، وما الذي يعرضه المنتج أو يغيّره. تجنّب التفاصيل الداخلية مثل جداول قاعدة البيانات، استدعاءات الواجهة البرمجية، وظائف الخلفية، أو أي إطار مستخدم. قد تهم هذه التفاصيل لاحقًا، لكنها تجعل السيناريوهات هشة وأكثر صعوبة في الاتفاق عليها.
السيناريو الجيد مستقل أيضًا. يجب أن يكون سهلاً تشغيله غدًا على بيئة نظيفة، دون الاعتماد على سيناريو آخر تم تشغيله أولاً. إذا اعتمد السيناريو على حالة سابقة، اذكرها بوضوح في الإعداد (مثلاً: "المستخدم لديه اشتراك نشط بالفعل").
تستخدم فرق كثيرة Given–When–Then لأنها تُجبر على الوضوح دون تحويل السيناريوهات إلى مواصفة كاملة.
السيناريو عادة "مكتمل" عندما يحتوي على هدف واحد، حالة بداية واضحة، إجراء محدد، ونتيجة مرئية. يجب أن تكون نتيجته ثنائية: أي شخص في الفريق يمكنه أن يقول "نجح" أو "فشل" بعد تشغيله.
مثال: "باستخدام مستخدم مسجل الدخول بدون وسيلة دفع محفوظة، عندما يختار باقة Pro ويؤكد الدفع، ثم يرى رسالة نجاح وتظهر الباقة كـ Pro في حسابه."
إذا كنت تبني في منشئ موجه بالدردشة مثل Koder.ai، التزم بنفس القاعدة: اختبر سلوك التطبيق المولّد (ما يختبره المستخدم)، لا كيف أنتجت المنصة الشيفرة.
أفضل صيغة هي تلك التي سيكتبها الناس ويقرأونها فعلًا. إذا كان نصف الفريق يستخدم سردًا طويلًا والنصف الآخر يكتب نقاطًا موجزة، ستحصل على فجوات وتكرارات ونقاشات حول الصياغة بدلًا من التركيز على الجودة.
Given–When–Then يعمل جيدًا عندما تكون الميزة تفاعلية ومعتمدة على الحالة. جدول بسيط يعمل جيدًا عندما يكون لديك قواعد إدخال-إخراج كثيرة ومتشابهة.
إذا كان فريقك منقسمًا، اختر صيغة واحدة لمدة 30 يومًا وعدّل لاحقًا. إذا ظل المراجعون يسألون "ما شكل النجاح؟" فهذه علامة للانتقال إلى Given–When–Then. إذا أصبحت السيناريوهات مطوَّلة جدًا، قد يكون الجدول أسهل للمسح.
أياً كانت الصيغة، قم بتوحيدها. احتفظ بنفس العناوين، نفس الزمن، ونفس مستوى التفصيل. اتفقوا أيضًا على ما لا تُدرجه: تفاصيل بكسل-مثالية للواجهة، تنفيذ داخلي، وحديث عن قواعد البيانات. يجب أن تصف السيناريوهات ما يراه المستخدم وما تضمنه النظام.
ضع السيناريوهات حيث يحدث العمل واحتفظ بها قريبة من الميزة.
الخيارات الشائعة تشمل تخزينها بجانب كود المنتج، في تذاكرك تحت قسم "سيناريوهات القبول"، أو في مساحة مستندات مشتركة صفحة لكل ميزة. إذا كنت تستخدم Koder.ai، يمكنك أيضًا الاحتفاظ بالسيناريوهات في وضع التخطيط حتى تبقى مع تاريخ البناء إلى جانب اللقطات ونقاط الاسترجاع.
المهم أن تجعلها قابلة للبحث، مصدرًا واحدًا للحقيقة، وأن تشترط وجود السيناريوهات قبل أن يعتبر التطوير "مبدوءًا".
ابدأ بإعادة كتابة المطالبة كهدف مستخدم مع خط نهاية واضح. استخدم جملة واحدة للهدف (من يريد ماذا)، ثم 2–4 معايير نجاح يمكنك التحقق منها دون جدال. إذا لم تتمكن من الإشارة إلى نتيجة مرئية، فليس لديك اختبار بعد.
بعد ذلك، فكك المطالبة إلى مدخلات، مخرجات، وقواعد. المدخلات هي ما يوفره المستخدم أو يختاره. المخرجات هي ما يظهره النظام، يحفظه، يرسله، أو يحظره. القواعد هي عبارات "فقط إذا" و"يجب" المخبأة بين السطور.
ثم تحقّق مما تعتمد عليه الميزة قبل أن تعمل. هنا تختبئ فجوات السيناريو: البيانات المطلوبة، أدوار المستخدم، الأذونات، التكاملات، وحالات النظام. على سبيل المثال، إذا كنت تبني تطبيقًا في Koder.ai، اشِر ما إذا كان يجب أن يكون المستخدم مسجلاً، لديه مشروع مُنشأ، أو يلبي أي متطلبات خطة قبل حدوث الإجراء.
الآن اكتب أصغر مجموعة من السيناريوهات التي تثبت أن الميزة تعمل: عادةً 1–2 مسارات سعيد، ثم 4–8 حالات حافة. اجعل كل سيناريو مركزًا على سبب واحد للفشل.
حالات الحافة الجيدة للاختيار منها (فقط ما يناسب المطالبة): مدخل مفقود أو غير صالح، عدم تطابق أذونات، تعارض حالة مثل "مُرسَل مسبقًا"، مشكلات اعتماد خارجي مثل انتهاء مهلة، وسلوك الاسترداد (رسائل خطأ واضحة، إعادة محاولة آمنة، لا حفظ جزئي).
اختم بتمرير سريع "ماذا يمكن أن يخطئ؟". ابحث عن حالات الفشل الصامت، الرسائل المربكة، والأماكن التي قد ينشئ فيها النظام بيانات خاطئة.
مسار السعيد هو أقصر طريق طبيعي حيث يسير كل شيء على ما يرام. إذا أبقيته مقصودًا مملًا، يصبح خط أساس موثوقًا يجعل حالات الحافة أسهل للاكتشاف لاحقًا.
سمِّ المستخدم الافتراضي والبيانات الافتراضية. استخدم دورًا حقيقيًا، لا "المستخدم": "عميل مسجل الدخول وبريده المؤكّد" أو "مشرف لديه صلاحية تعديل الفوترة." ثم حدد أبسط بيانات عيّنة معقولة: مشروع واحد، عنصر واحد في القائمة، وسيلة دفع محفوظة واحدة. هذا يبقي السيناريوهات ملموسة ويقلل الافتراضات المخفية.
اكتب أقصر طريق إلى النجاح أولًا. احذف الخطوات الاختيارية وتدفقات البدائل. إذا كانت الميزة "إنشاء مهمة"، فلا يجب أن يتضمن المسار السعيد التصفية أو الفرز أو التحرير بعد الإنشاء.
طريقة بسيطة للحفاظ على التركيز هي تأكيد أربعة أشياء:
ثم أضف متغيرًا واحدًا يغيّر متغيرًا واحدًا فقط. اختر المتغير الأكثر احتمالًا للتسبب في كسر لاحقًا، مثل "عنوان طويل" أو "المستخدم لا يملك عناصر موجودة"، وحافظ على بقية الشروط دون تغيير.
مثال: إذا قالت مطالبتك "أضف إشعار 'Snapshot created' بعد حفظ لقطة"، فإن المسار السعيد هو: ينقر المستخدم على إنشاء لقطة، يرى حالة تحميل، يحصل على "Snapshot created"، وتظهر اللقطة في القائمة بالطابع الزمني الصحيح. متغير ذو متغير واحد يمكن أن يكون نفس الخطوات لكن باسم فارغ وقاعدة تسمية افتراضية واضحة.
حالات الحافة هي المكان الذي تختبئ فيه معظم الأخطاء، ولا تحتاج إلى مجموعة ضخمة للإمساك بها. لكل مطالبة ميزة، اختر مجموعة صغيرة تعكس السلوك الحقيقي وأنماط الفشل الحقيقية.
فئات شائعة للاختيار منها:
ليست كل ميزة بحاجة لكل فئة. صندوق بحث يهتم أكثر بالمدخلات. مسار الدفع يهتم أكثر بالتكامل والبيانات.
اختر حالات حافة تناسب المخاطر: تكلفة الفشل العالية (مال، أمان، خصوصية)، التكرار العالي، التدفقات السهلة للكسر، أو أخطاء سابقة معروفة.
مثال: لميزة "يغيّر المستخدم خطة الاشتراك"، سيناريوهات غالبًا ما تُجدي نفعًا هي انتهاء الجلسة عند الخروج، نقرة مزدوجة على "تأكيد"، وانتهاء مهلة موفر الدفع التي تترك الخطة دون تغيير مع ظهور رسالة واضحة.
مثال مطالبة ميزة (بلغة بسيطة):
"عندما أكسر شيئًا، أريد أن أرجع تطبيقي إلى لقطة سابقة حتى تعود آخر نسخة عاملة للحياة مجددًا."
فيما يلي مجموعة سيناريوهات مدمجة. كل سيناريو قصير، لكنه يثبت نتيجة.
S1 [ضروري] العودة إلى أحدث لقطة
Given أنا مسجل الدخول وأنا مالك التطبيق
When أختار "Rollback" وأؤكد
Then يتم نشر اللقطة السابقة وتُظهر حالة التطبيق أن النسخة الجديدة نشطة
S2 [ضروري] العودة إلى لقطة محددة
Given أعرض قائمة اللقطات لتطبيقي
When أختار اللقطة "A" وأؤكد الرجوع
Then تصبح اللقطة "A" النسخة النشطة ويمكنني رؤية تاريخ إنشائها
S3 [ضروري] غير مسموح (مصادقة)
Given أنا مسجل الدخول لكن لا أملك وصولًا لهذا التطبيق
When أحاول الرجوع
Then أرى خطأ وصول ولا يبدأ أي رجوع
S4 [ضروري] اللقطة غير موجودة (تحقق)
Given معرّف لقطة غير موجود (أو تم حذفه)
When أحاول الرجوع إليه
Then أحصل على رسالة واضحة "اللقطة غير موجودة"
S5 [ضروري] إرسال مزدوج (تكرارات)
Given أضغط "تأكيد الرجوع" مرتين بسرعة
When يُرسل الطلب الثاني
Then يُشغّل رجوع واحد فقط وأرى نتيجة واحدة
S6 [ضروري] فشل النشر (أخطاء)
Given يبدأ الرجوع
When يفشل النشر
Then تبقى النسخة النشطة الحالية حيّة وتُعرض رسالة الخطأ
S7 [من الجيد امتلاكه] انتهاء مهلة أو فقدان الاتصال
Given انقطع الاتصال أثناء الرجوع
When أعيد تحميل الصفحة
Then أستطيع رؤية ما إذا كان الرجوع لا يزال جارًٍا أو قد انتهى
S8 [من الجيد امتلاكه] بالفعل على تلك اللقطة
Given اللقطة "A" هي النشطة بالفعل
When أحاول الرجوع إلى اللقطة "A"
Then يُقال لي أنه لا شيء تغيّر ولا يبدأ نشر جديد
كل سيناريو يجيب عن ثلاثة أسئلة: من يقوم به، ماذا يفعل، وما الذي يجب أن يكون صحيحًا بعد ذلك.
الهدف ليس "اختبار كل شيء". الهدف هو تغطية المخاطر التي قد تضر المستخدمين، دون خلق كومة من السيناريوهات التي لا يُشغّلها أحد.
خدعة عملية هي تصنيف السيناريوهات حسب كيفية استخدامك المتوقع لها:
قصر نفسك على سيناريو واحد لكل خطر مميز. إذا فشل سيناريوان لنفس السبب، فغالبًا تحتاج واحدًا فقط. "صيغة بريد إلكتروني خاطئة" و"بريد إلكتروني مفقود" مخاطرتان مختلفتان. لكن "بريد مفقود في الخطوة 1" و"بريد مفقود في الخطوة 2" قد تكونان نفس الخطر إذا كانت القاعدة نفسها.
تجنب أيضًا تكرار خطوات واجهة المستخدم عبر سيناريوهات كثيرة. اختصر الأجزاء المكررة وركّز على ما يتغير. هذا مهم أكثر عند البناء في أداة دردشة مثل Koder.ai لأن الواجهة قد تتغير بينما تبقى قاعدة العمل نفسها.
أخيرًا، قرر ما الذي تتحقق منه الآن مقابل لاحقًا. بعض الفحوصات أفضل يدويًا في البداية ثم تُؤتمت عندما تستقر الميزة:
يجب أن يحميك السيناريو من المفاجآت، لا يصف كيف يخطط الفريق لبناء الميزة.
الخطأ الأكثر شيوعًا هو تحويل هدف المستخدم إلى قائمة تحقق تقنية. إذا قال السيناريو "API يعيد 200" أو "الجدول X يحتوي عمود Y"، فأنت تُقفل على تصميم واحد ولا تزال لا تثبت أن المستخدم حصل على ما يحتاجه.
مشكلة أخرى هي دمج أهداف متعددة في سيناريو طويل. يبدو كسفر كامل، ولكن عندما يفشل، لا يعرف أحد لماذا. يجب أن يجيب كل سيناريو عن سؤال واحد.
كن حذرًا من حالات الحافة التي تبدو ذكية لكنها ليست واقعية. "المستخدم لديه 10 ملايين مشروع" أو "الشبكة تسقط كل ثانيتين" نادرًا ما تعكس الإنتاج وصعب استنساخها. اختر حالات حافة يمكنك إعدادها في دقائق.
تجنّب أيضًا النتائج المبهمة مثل "يعمل"، "لا أخطاء"، أو "اكتمل بنجاح". هذه الكلمات تُخفي النتيجة الدقيقة التي يجب التحقق منها.
إذا كنت تبني شيئًا مثل ميزة Koder.ai "تصدير الشيفرة المصدرية"، سيناريو ضعيف هو: "عندما ينقر المستخدم تصدير، يضغط النظام على الملف ويعيد 200." هذا يختبر تنفيذًا، لا الوعد.
سيناريو أفضل هو: "Given مشروع يحتوي على لقطتين، عندما يصدر المستخدم، then التنزيل يحتوي على شيفرة اللقطة الحالية وسجل التصدير يسجل من صدّر ومتى."
لا تنسَ مسارات "لا": "Given مستخدم بدون صلاحية التصدير، when يحاول التصدير، then الخيار مخفي أو محجوب، ولا يُنشأ سجل تصدير." سطر واحد يمكنه حماية كل من الأمان وسلامة البيانات.
قبل أن تعتبر مجموعة السيناريوهات "مكتملة"، اقرؤها كمستخدم متشدد وكقاعدة بيانات. إذا لم تستطع أن تقول ما يجب أن يكون صحيحًا قبل بدء الاختبار، أو ماذا يعني "نجاح"، فهي ليست جاهزة.
مجموعة جيدة صغيرة لكنها محددة. يجب أن تستطيع تسليمها لشخص لم يكتب الميزة والحصول على نفس النتائج.
استخدم هذا الفحص السريع للموافقة (أو الإعادة):
إذا كنت تُولّد السيناريوهات في منشئ دردشة مثل Koder.ai، جَرّها وفق نفس المعيار: لا "يعمل كما هو متوقع" غامض. اطلب مخرجات مرصودة وتغييرات محفوظة، ثم وافق فقط على ما يمكنك التحقق منه.
اجعل كتابة السيناريوهات خطوة فعلية في عمليتك، لا مهمة تنظيف في النهاية.
اكتب السيناريوهات قبل بدء التنفيذ، بينما الميزة لا تزال رخيصة التغيير. هذا يُجبر الفريق على الإجابة عن الأسئلة المحرجة مبكرًا: ماذا يعني "نجاح"، ماذا يحدث على مدخل سيّئ، وما الذي لن ندعمه الآن.
استخدم السيناريوهات كتعريف مشترك لـ "مكتمل". المنتج يملك النية، فِرق ضمان الجودة تملك التفكير بالمخاطر، والهندسة تملك القابلية للتنفيذ. عندما يستطيع الثلاثة قراءة نفس مجموعة السيناريوهات والاتفاق عليها، تتجنّب شحن شيء "مكتمل" لكنه غير مقبول.
سير عمل عملي يتحمل في معظم الفرق:
إذا كنت تبني في Koder.ai (koder.ai)، مسودة السيناريوهات أولًا ثم استخدام وضع التخطيط يمكن أن يساعدك على مطابقة كل سيناريو مع الشاشات، قواعد البيانات، والنتائج المرئية قبل أن تولّد أو تعدل الشيفرة.
للتغييرات الخطرة، خذ لقطة قبل البدء في التكرار. إذا كسرَت حالة حافة جديدة تدفقًا عاملًا، يمكن لإرجاع الحالة أن ينقذك من قضاء يوم كامل في فك أثر الآثار الجانبية.
احتفظ بالسيناريوهات بجانب طلب الميزة (أو داخل نفس التذكرة) وعاملها كمتطلبات مُؤرَّخة. عندما تتطور المطالبات، يجب أن تتطور مجموعة السيناريوهات معها، وإلا سيَنْحرف تعريفك لـ "مكتمل" بصمت.
ابدأ بجملة واحدة تحدد هدف المستخدم وخط النهاية.
ثم قسّم المطالبة إلى:
من هناك، اكتب 1–2 مسارات سعيد زائد 4–8 حالات حافة تناسب المخاطر الحقيقية (الأذونات، التكرارات، انتهاء مهلة الموفر، البيانات المفقودة).
لأن المطالبات تُخفي الافتراضات. قد تقول المطالبة "احفظ" دون تحديد ما إذا كان المقصود مسودة أم منشور، ماذا يحدث عند الفشل، أو من المسموح له القيام بذلك.
السيناريوهات تُجبرك على تسمية القواعد مبكرًا، قبل أن ترسل أخطاء مثل إرساليات مكررة، أو عدم تطابق الأذونات، أو نتائج غير متسقة.
استخدم Given–When–Then عندما تكون الميزة تفاعلية وحالة-معتمدة.
استخدم جدول مدخل/مخرجات بسيط عندما يكون لديك الكثير من قواعد المدخل/المخرج المتشابهة.
اختر صيغة واحدة لمدة شهر وطبّقها (نفس الزمن، نفس مستوى التفصيل). أفضل صيغة هي التي سيستمر فريقك في استخدامها فعليًا.
سيناريو جيد هو:
يُعتبر "مكتملًا" عندما يستطيع أي شخص تشغيله والموافقة على النتيجة بدون نقاش.
ركّز على السلوك المرصود:
تجنب تفاصيل التنفيذ (جداول قاعدة بيانات، رموز استجابة API، وظائف خلفية، أو أطر العمل). هذه التفاصيل تتغير كثيرًا ولا تثبت أن المستخدم حصل على النتيجة المطلوبة.
اكتب المسار الأكثر مملًا وطبيعيًا حيث يسير كل شيء على ما يرام:
ثم تحقق من أربعة أشياء: الشاشة/الحالة الصحيحة، رسالة النجاح، حفظ البيانات، وأن المستخدم يستطيع المتابعة للخطوة المنطقية التالية.
اختر حالات الحافة بناءً على المخاطر والتكرار:
استهدف سيناريو واحد لكل خطر مميز، لا كل تباين ممكن.
اجعلها آمنة وواضحة:
سيناريو الفشل يجب أن يثبت أن النظام لا يفسد البيانات ولا يضلّل المستخدم.
عامل مخرجات Koder.ai مثل أي تطبيق آخر: اختبر ما يواجهه المستخدم، لا كيف نُنشئت الشيفرة.
نهج عملي:
خزنها حيث يحدث العمل واحتفظ بمصدر واحد للحقيقة:
إذا كنت تستخدم Koder.ai، احتفظ بالسيناريوهات في وضع التخطيط حتى تبقى مرتبطة بتاريخ البناء. والأهم: اشترط وجود السيناريوهات قبل بدء التطوير.