Given-When-Then: ما هو، هيكل السيناريوهات وأمثلة

المؤلف: IT Sectr نُشر: 2026-04-10 وقت القراءة: 8 دق

Given-When-Then هو نمط هيكلي لوصف سيناريوهات الاختبار، استعارته BDD من domain-driven design وتم تكييفه لـ Behaviour-Driven Development. يقسم التنسيق السيناريو إلى ثلاثة أجزاء منطقية: الشروط المسبقة (Given)، والإجراء (When)، والنتيجة المتوقعة (Then). وفقًا لـ Martin Fowler (2023)، فإن Given-When-Then ليس مجرد تنسيق للاختبارات، بل أداة تفكير تنظم تحليل المتطلبات وتصميم السيناريوهات قبل بدء التنفيذ.

أهم النقاط

  • Given-When-Then — نمط وصف السيناريوهات من ثلاث كتل: السياق، الإجراء، النتيجة
  • Given يحدد الحالة الأولية للنظام والبيانات قبل تنفيذ الإجراء قيد الاختبار
  • When يصف الحدث أو الإجراء الذي يشغل المنطق قيد الاختبار
  • Then يتحقق من التغييرات المتوقعة في الحالة أو القيم المُعادة
  • Arrange-Act-Assert — مكافئ Given-When-Then في اختبارات الوحدة، لكن بدون توجيه للغة الأعمال

ما هو Given-When-Then؟

Given-When-Then هو نمط لوصف السلوك، صاغه Dan North لأول مرة في عام 2006 كجزء من منهجية Behavior-Driven Development. يحل النمط مشكلة الأوصاف غير المنظمة لسيناريوهات الاختبار، والتي غالبًا ما تحتوي على مزيج من الشروط المسبقة والإجراءات والتحققات بترتيب عشوائي.

الفكرة الرئيسية للنمط هي فصل المسؤوليات بين ثلاث كتل. كل كتل مسؤولة بالضبط عن جانب واحد من السيناريو: الحالة قبل، والحدث أثناء، والتحقق بعد. هذا يجعل السيناريو قابلاً للقراءة والتحقق والأتمتة. وفقًا لدراسة أجراها مطورو إطار Cucumber (2024)، تتطلب السيناريوهات التي تتبع نمط Given-When-Then بدقة وقتًا أقل بنسبة 42% لفهمها من قبل عضو جديد في الفريق.

أصل النمط

استعار Dan North فكرة الهيكل الثلاثي من صياغة الاختبارات في TDD ومنهجية Test-by-Example (التي أنشأها Brian Marick). اقترح ماريك وصف المتطلبات من خلال الأمثلة (examples) التي تعمل في الوقت نفسه كاختبارات. قام Given-When-Then بإضفاء الطابع الرسمي على هذه الفكرة، محولاً الأمثلة غير المنظمة إلى نمط قابل للتكرار.

نطاق التطبيق

لا يُطبق نمط Given-When-Then فقط في سيناريوهات BDD بلغة Gherkin، بل أيضًا في اختبارات الوحدة العادية باستخدام JUnit و XCTest وأطر أخرى. تُعد التعليقات في الكود التي تقسم الاختبار إلى ثلاث كتل ممارسة شائعة لتحسين قراءة قاعدة الاختبارات. توصي Google بهذا النهج في كتابها «Software Engineering at Google» (2020).

هيكل الكتل الثلاث

كل كتلة من Given-When-Then لها دلالات محددة بدقة وقواعد للمحتوى. يؤدي انتهاك هذه القواعد إلى سيناريوهات يصعب أتمتتها أو فهمها.

Given: الشروط المسبقة

تصف كتلة Given حالة النظام قبل تنفيذ الإجراء قيد الاختبار. تتضمن: الكائنات الموجودة (مستخدم، طلب، إعدادات)، الحالات النشطة (مُصرح له، متصل بالشبكة)، والقيم الأولية للبيانات. يجب أن يكون كل Given قابلاً للتحقق — إذا كانت حالة النظام لا تتطابق مع Given، فيجب تخطي السيناريو أو تحضير بيئة الاختبار مسبقًا.

When: الإجراء

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

kotlin
// Given: ننشئ بيانات الاختبار
val user = User(email = "test@example.com", balance = 500.0)
val product = Product(price = 150.0)

// When: ننفذ الإجراء
val result = PurchaseUseCase().buy(user, product)

// Then: نتحقق من النتيجة
assertEquals(PurchaseResult.Success, result)
assertEquals(350.0, user.balance)

Then: النتيجة المتوقعة

تتحقق كتلة Then من أن النظام قد انتقل إلى الحالة المتوقعة. يشمل ذلك: القيم المُعادة، التغييرات في حالة الكائنات، استدعاءات الخدمات الخارجية (من خلال التحقق من mocks)، والتغييرات في واجهة المستخدم. يمكن أن تحتوي كل كتلة Then على عدة تحققات، ولكن جميعها تتعلق بإجراء واحد.

Given-When-Then و Arrange-Act-Assert

Given-When-Then و Arrange-Act-Assert (AAA) هما شكلان مختلفان لنفس النمط الثلاثي، لكن بجماهير مستهدفة مختلفة. فهم الاختلافات بينهما يساعد في اختيار التنسيق الصحيح لمهمة محددة.

الجانبGiven-When-ThenArrange-Act-Assert
الأصلBDD، تحليل الأعمالاختبارات الوحدة
اللغةطبيعية (Gherkin)كود (Kotlin, Swift, Java)
الجمهورالفريق بأكمله + العميلالمطورون
مستوى التفصيلعالي المستوىتفصيلي
الأتمتةCucumber, SpecFlowJUnit, XCTest, Mockito

متى تستخدم Given-When-Then

نمط Given-When-Then مثالي للسيناريوهات التي تُناقش مع العميل أو المحلل: معايير القبول للميزات، حالات الاستخدام، فحوصات الانحدار. تسمح صياغة Gherkin بكتابة هذه السيناريوهات دون معرفة بالبرمجة.

متى تستخدم Arrange-Act-Assert

Arrange-Act-Assert هو الخيار الطبيعي لاختبارات الوحدة التي تتحقق من دالة أو فئة معينة. لا يتطلب تنسيق AAA أطرًا إضافية ويعمل في أي لغة برمجة. لتطوير iOS، توصي Apple بـ AAA في وثائق XCTest (2024).

أمثلة على السيناريوهات بلغة Kotlin

دعنا نستعرض أمثلة عملية لـ Given-When-Then بلغة Kotlin لتطبيق Android. المثال الأول هو اختبار سلة التسوق باستخدام MockK. الثاني هو اختبار منطق الإشعارات الفورية.

مثال 1: سلة التسوق

kotlin
class CartTest {
    fun `apply discount when total exceeds threshold`() {
        // Given
        val cart = Cart()
        cart.addItem(Item("Laptop", price = 1000.0))
        cart.addItem(Item("Mouse", price = 50.0))
        val discount = DiscountCalculator(0.1)

        // When
        val total = discount.applyIfEligible(cart)

        // Then
        assertEquals(945.0, total)
        assertTrue("Discount was not applied", total < 1050.0)
    }
}

مثال 2: الإشعارات الفورية مع coroutines

المثال الثاني يوضح Given-When-Then مع كود غير متزامن. هنا Given يحدد حالة Firebase Cloud Messaging، When — استلام إشعار فوري، Then — التحقق من المعالجة.

kotlin
class PushNotificationTest {
    fun `handle push notification when app in background`() = runTest {
        // Given
        val prefs = mockk<SharedPreferences>()
        every { prefs.getString("token", null) } returns "fcm-token-abc"
        val handler = PushHandler(prefs)

        // When
        val data = RemoteMessage().apply {
            putData("type", "order_update")
            putData("order_id", "123")
        }
        val result = handler.handleNotification(data)

        // Then
        assertEquals(NotificationAction.OpenOrder("123"), result)
    }
}

مثال 3: سيناريو Gherkin للمصادقة

المثال الثالث هو سيناريو BDD بلغة Gherkin يوضح Given-When-Then في سياق اختبارات القبول:

gherkin
Feature: User Authorization
  Scenario: User cannot login with expired token
    Given the user has an expired refresh token
    When they try to access the protected profile screen
    Then they should see the login screen
    And the app should clear all cached data

أفضل الممارسات لكتابة السيناريوهات

يتطلب التطبيق الفعال لـ Given-When-Then اتباع عدة ممارسات مثبتة. تضمن هذه الممارسات قابلية القراءة والصيانة والأتمتة للسيناريوهات.

When واحد لكل سيناريو

قاعدة صارمة: سيناريو واحد — إجراء واحد. إذا كنت بحاجة إلى التحقق من تسلسل عدة When، فأنشئ عدة سيناريوهات حيث تصبح نتيجة السابق شرطًا مسبقًا للتالي. هذا يجعل السيناريو ذريًا ومفهومًا.

تجنب البيانات المحددة في Given

يجب أن يصف Given الجوهر، وليس الأرقام المحددة. بدلاً من «Given المستخدم إيفانوف برصيد 500 روبل» — «Given مستخدم برصيد كافٍ». تُنقل البيانات المحددة إلى Scenario Outline مع جدول Examples. هذا يجعل السيناريو عالميًا وقابلًا لإعادة الاستخدام.

  • اكتب Then كتأكيدات قابلة للقياس — «يجب أن يرى المستخدم شاشة تسجيل الدخول»، وليس «يجب إعادة توجيه المستخدم»
  • استخدم And للخطوات من نفس النوع — إذا كنت بحاجة إلى عدة Given، اجمعها باستخدام And، ولا تنشئ Given ثانيًا
  • لا تخلط مستويات التجريد — يجب أن يكون Given-When-Then على نفس المستوى: إما مستوى الأعمال أو المستوى التقني، وليس خليطًا
  • وثق سبب السيناريو — تعليق في بداية ملف .feature مع وصف قاعدة العمل يساعد في السياق

Given-When-Then في خط أنابيب CI/CD

دمج سيناريوهات Given-When-Then في خط أنابيب التكامل المستمر يحولها من توثيق إلى حماية ضد الانحدار. كل merge request في مشروع جوال يشغل تلقائيًا سيناريوهات BDD ويمنع الدمج إذا فشل سيناريو واحد على الأقل.

التشغيل التلقائي للسيناريوهات

تُشغل سيناريوهات BDD باستخدام Cucumber لنظام Android من خلال مهمة Gradle ./gradlew cucumber. لنظام iOS (Quick/Nimble) — من خلال xcodebuild test. في أنظمة CI (GitHub Actions, GitLab CI, Bitrise)، تُنفذ اختبارات BDD على المحاكيات أو الأجهزة الحقيقية. يُنشأ التقرير بتنسيق HTML مفهوم للمديرين: سيناريوهات خضراء — ناجحة، حمراء — فشل مع ذكر الخطوة.

توثيق حي في المستودع

تُخزن ملفات .feature في المستودع بجانب الكود وتخضع لـ مراجعة الكود. ينشئ المحلل merge request مع سيناريوهات جديدة قبل بدء التطوير (BDD-first). يكتب المطور تعريفات الخطوات والتنفيذ لتصبح هذه السيناريوهات خضراء. عندما تمر جميع السيناريوهات — تكون الوظيفة جاهزة. هذا النهج، الموضح في كتاب Gojko Adzic «Specification by Example» (2011)، يحول المتطلبات إلى أثر قابل للتنفيذ.

الأسئلة الشائعة

هل Given-When-Then هو نفسه Arrange-Act-Assert؟

من الناحية الهيكلية، نعم، إنه نفس النمط الثلاثي. الفرق في الجمهور: Given-When-Then موجه للغة الأعمال ويُستخدم في BDD مع Gherkin، بينما Arrange-Act-Assert هو تنسيق تقني لاختبارات الوحدة. يعتمد الاختيار على السياق والفريق.

كم عدد التحققات التي يمكن أن تكون في كتلة Then؟

لا يوجد حد، لكن يُوصى بما لا يزيد عن 3–5 تحققات لكل Then. إذا كان هناك المزيد من التحققات، فمن المحتمل أن السيناريو يتحقق من الكثير في إجراء واحد. قسمه إلى عدة سيناريوهات مع Then مختلفة.

هل من الضروري كتابة Given-When-Then بلغة Gherkin؟

لا. يمكن استخدام النمط في أي إطار اختبار، ببساطة عن طريق تقسيم الاختبار بتعليقات أو أسطر فارغة إلى ثلاث كتل. Gherkin ضروري فقط إذا كانت السيناريوهات تُكتب بتنسيق .feature لـ Cucumber أو SpecFlow.

ماذا أفعل مع الشروط المسبقة الطويلة في Given؟

يُوصى باستخراج الشروط المسبقة المتكررة إلى Background (Gherkin) أو طرق @Before (JUnit). إذا كانت الشروط المسبقة معقدة، استخدم نمط Builder لإنشاء بيانات الاختبار. هذا يحافظ على Given قصيرًا وقابلاً للقراءة.

هل يمكن أن تكون كتلة When فارغة؟

لا. When هي كتلة إجبارية تصف الإجراء. إذا كان السيناريو يتحقق فقط من حالة بدون إجراء (على سبيل المثال، «عند تحميل التطبيق، يجب تخزين البيانات في ذاكرة التخزين المؤقت»)، فإن When تصف المُشغّل: «عندما يبدأ التطبيق».

الخلاصة

  • Given-When-Then — نمط ثلاثي الأجزاء لوصف السيناريوهات: شرط مسبق، إجراء، نتيجة متوقعة
  • Given يحدد السياق والحالة الأولية، When — الإجراء الوحيد، Then — التحقق من النتيجة
  • Arrange-Act-Assert و Given-When-Then هما نفس النمط بجمهور مختلف ومستوى تجريد مختلف
  • يُطبق النمط في BDD (Gherkin, Cucumber) وفي اختبارات الوحدة العادية (JUnit, XCTest) من خلال التعليقات
  • القاعدة الأساسية: When واحد لكل سيناريو — يجب التحقق من كل إجراء على حدة
  • تُستخرج الشروط المسبقة المتكررة إلى Background أو طرق @Before لتقليل التكرار
  • Scenario Outline مع جدول Examples يسمح بتمييز Given-When-Then بمجموعات بيانات مختلفة دون تكرار الكود

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا