الاختبار في خطوط CI/CD

الاختبار في خطوط التكامل والتسليم المستمرين (CI/CD testing) هو جزء ضمان الجودة الذي يعمل آلياً في كل مرة يتغير فيها الكود: يبني خط الأنابيب (pipeline) التغيير، ويشغّل الفحوص بترتيب مقصود، وينشر النتائج، ويقرر ما إذا كان يجوز للتغيير أن يتقدم نحو الإنتاج. بالنسبة للمختبِر، خط الأنابيب هو المكان الذي يجري فيه معظم فحص الانحدار اليوم، وحيث تُرى إخفاقات الاختبار أول مرة، وحيث يكون قرار الإصدار مدعوماً بالأدلة أو غير مدعوم.

هذا الدليل هو مدخل الموضوع. يشرح التكامل المستمر والتسليم المستمر والنشر المستمر، ومراحل الاختبار في خط الأنابيب ولماذا يهم ترتيبها، وبوابات الجودة، والتقارير والمخرجات، والبيئات والأسرار، والتنفيذ المتوازي، وسياسة الاختبارات المتذبذبة، وكيف تفرز خط أنابيب أحمر. ويتعمق دليلان أضيق: أحدهما يقارن اختبار الدخان والسلامة والانحدار ويبيّن كيف تختار اختبارات الانحدار، والآخر يغطي التحقق بعد النشر — اختبارات الدخان بعد النشر وإصدارات الكناري والتراجع.

التكامل المستمر والتسليم المستمر والنشر المستمر

التكامل المستمر (Continuous Integration) هو ممارسة دمج عمل كل مطوّر في الفرع الرئيسي المشترك بشكل متكرر — يومياً على الأقل — مع التحقق من كل دمج ببناء آلي يختبر نفسه. ويضيف وصف مارتن فاولر الأكثر استشهاداً القواعد التي تجعله ينجح: أبقِ البناء سريعاً، وأصلح البناء المكسور فوراً، واعتبر الفرع الرئيسي الأحمر مشكلة الجميع. التكامل المستمر عادة فريق تدعمها أداة، لا الأداة نفسها؛ فخادم CI يعمل مرة في الأسبوع على فرع طويل العمر ليس تكاملاً مستمراً.

التسليم المستمر (Continuous Delivery) يوسّع التكامل المستمر بحيث يكون كل تغيير يجتاز خط الأنابيب قابلاً للإصدار: يُبنى مرة واحدة، ويُختبر في بيئات شبيهة بالإنتاج، ويمكن نشره في الإنتاج بضغطة زر. ويبقى قرار النشر قراراً بشرياً أو تجارياً. أما النشر المستمر (Continuous Deployment) فيزيل هذا القرار: كل تغيير يجتاز جميع المراحل الآلية يذهب إلى الإنتاج تلقائياً. الفرق مهم للمختبِرين لأنه في النشر المستمر لا تبقى نقطة تفتيش يدوية — فكل ما لا يفحصه خط الأنابيب لا يفحصه أحد قبل أن يراه المستخدمون.

  • التكامل المستمر — دمج متكرر في الفرع الرئيسي، يُتحقق من كل دمج ببناء واختبارات آلية.
  • التسليم المستمر — كل تغيير ناجح قابل للنشر؛ وشخص ما يختار موعد الإصدار.
  • النشر المستمر — كل تغيير ناجح يُنشر تلقائياً؛ ويصبح التحقق بعد النشر آخر شبكة أمان.
  • في الثلاثة، الاختبارات الآلية هي الدليل. وخط الأنابيب جدير بالثقة بقدر الاختبارات التي يشغّلها والبوابات التي يفرضها.

مراحل الاختبار في خط الأنابيب ولماذا يهم ترتيبها

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

تختلف المراحل الدقيقة من فريق لآخر، لكن معظم خطوط الأنابيب تتقارب نحو ترتيب متشابه. وينبغي أن يكون لكل مرحلة ميزانية زمنية؛ وحين تتجاوزها المرحلة، إما أن يوازيها الفريق، أو ينقل الاختبارات البطيئة إلى مرحلة لاحقة، أو يزيل التغطية المكررة.

  • مرحلة الإيداع (Commit stage، دقائق) — الفحوص الساكنة (التدقيق، وفحص الأنواع، والتنسيق، وفحص الاعتماديات والأسرار)، واختبارات الوحدة، واختبارات المكوّنات مع استبدال الاعتماديات ببدائل اختبار. تعمل عند كل دفع وكل طلب دمج.
  • مرحلة التكامل والواجهة البرمجية — التطبيق مقابل قواعد بيانات وطوابير وحاويات خدمات حقيقية؛ واختبارات API تُفحص مقابل العقد (OpenAPI). هنا يُتحقق من معظم قواعد العمل بتكلفة معقولة.
  • مرحلة الاختبار الشامل / الواجهة (E2E/UI) — مجموعة صغيرة من رحلات المستخدم الحرجة عبر متصفح أو جهاز حقيقي؛ وهي الأبطأ والأكثر عرضة للتذبذب، لذا تُبقى صغيرة عمداً.
  • المرحلة غير الوظيفية — دخان أداء قصير (دقائق من الحمل على نقاط النهاية الأساسية مع عتبات لزمن الاستجابة ومعدل الخطأ)، وفحوص أمان (تحليل ساكن، وثغرات الاعتماديات، وفحص ديناميكي أساسي)، وفحوص إمكانية الوصول على الصفحات الرئيسية.
  • مرحلة ما بعد النشر — اختبارات الدخان وفحوص الصحة على البيئة التي نُشرت للتو، ثم المراقبة الاصطناعية. يغطيها دليل التحقق من النشر بالتفصيل.
  • المراحل المجدولة — حزمة الانحدار الكاملة، واختبارات الحمل الطويلة، وفحوص الأمان الكاملة تعمل ليلياً أو أسبوعياً بدلاً من كل تغيير، وتُبلغ مالكاً يتصرف حيال الإخفاقات.
مراحل التغيير الواحد بالترتيب: تعمل الفحوص الأرخص والأسرع أولاً، ولا تصل إلى كل مرحلة لاحقة إلا التغييرات التي اجتازت ما قبلها.
  1. 1مرحلة الإيداعدقائق. فحوص ساكنة واختبارات الوحدة والمكوّنات؛ عند كل دفع وطلب دمج

    بوابة: تمرّ التغييرات الناجحة فقط

  2. 2التكامل والواجهة البرمجيةقواعد بيانات وطوابير وخدمات حقيقية؛ اختبارات API مقابل العقد

    بوابة: تمرّ التغييرات الناجحة فقط

  3. 3الاختبار الشامل / الواجهةمجموعة صغيرة من رحلات المستخدم الحرجة في متصفح أو جهاز حقيقي

    بوابة: تمرّ التغييرات الناجحة فقط

  4. 4غير الوظيفيةدخان أداء قصير، فحوص أمان، فحوص إمكانية الوصول

    بوابة: النشر — تلقائي في النشر المستمر؛ ويقرره شخص في التسليم المستمر

  5. 5ما بعد النشراختبارات دخان وفحوص صحة على البيئة المنشورة، ثم مراقبة اصطناعية

أولاً: الأرخص والأسرع والأكثر احتمالاً للفشللاحقاً: البطيئة والمكلفة والمعتمدة على البيئة

خارج التسلسل
  • مجدولة: ليلياً أو أسبوعياًحزمة الانحدار الكاملة واختبارات الحمل الطويلة وفحوص الأمان الكاملة، تُبلغ مالكاً يتصرف حيال الإخفاقات

ترتيب توضيحي: تختلف المراحل الدقيقة من فريق لآخر.

جرّبها: مولّد حالات اختبار من OpenAPI جرّبها: مولّد اختبارات الطلبات المتزامنة جرّبها: محلّل زمن الاستجابة

مثال: خط أنابيب بمراحل الإيداع وAPI والاختبار الشامل والنشر

مسار العمل أدناه مثال مكتوب بصيغة GitHub Actions. يشغّل الفحوص الساكنة واختبارات الوحدة أولاً، ثم اختبارات API مقابل حاوية خدمة PostgreSQL مؤقتة مع الترحيلات وبيانات بذر اصطناعية، ثم حزمة المتصفح مقسّمة إلى أربعة أجزاء متوازية (shards)، وعلى الفرع الرئيسي ينشر إلى بيئة staging ويشغّل سكربت دخان. كل مهمة اختبار ترفع تقاريرها ومخرجاتها حتى عند الفشل (`if: always()`)، لأن الإخفاق بلا أدلته هو أغلى أنواع الإخفاق تحقيقاً. ويعبّر GitLab CI وJenkins عن البنية نفسها بمراحل ومهام في `.gitlab-ci.yml` أو ملف Jenkinsfile.

  • `needs` يجعل الترتيب صريحاً: أجزاء الاختبار الشامل لا تبدأ أبداً إن فشلت اختبارات الوحدة أو API.
  • `concurrency` مع `cancel-in-progress` يوقف التشغيل الجاري لطلب دمج حين يبدأ تشغيل أحدث بسبب دفع جديد إلى طلب الدمج نفسه، فيوفّر وقت المشغّلات. أما على الفرع الرئيسي والجدولة الليلية، وهما تشتركان في مجموعة refs/heads/main، فلا يُلغى تشغيل جارٍ أبداً، فلا يُقطع نشرٌ في منتصفه؛ لكن التشغيل الذي ما زال منتظراً (pending) في المجموعة يُلغى حين يدخل الطابور تشغيل أحدث، وهذا هو السلوك الافتراضي لكل مجموعة تزامن.
  • `timeout-minutes` يحوّل الاختبار المعلّق إلى إخفاق ظاهر بدلاً من مهمة تنتظر ساعات.
  • رمز النشر يأتي من مخزن الأسرار في المنصة؛ وكلمة مرور قاعدة البيانات مكتوبة حرفياً فقط لأن الحاوية تعيش مهمة واحدة.
  • الجدولة تعمل على الفرع الافتراضي؛ وأوقات cron في GitHub Actions بتوقيت UTC ما لم تحدد الجدولة منطقة زمنية.
# Example pipeline (GitHub Actions syntax). Adapt job names, scripts and versions to your project.
name: ci

on:
  pull_request:
  push:
    branches: [main]
  schedule:
    - cron: "0 1 * * *"   # nightly full regression, 01:00 UTC

concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
  commit-stage:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: 24
          cache: npm
      - run: npm ci
      - run: npm run lint
      - run: npm run typecheck
      - run: npm run test:unit          # writes reports/junit-unit.xml
      - uses: actions/upload-artifact@v7
        if: always()
        with:
          name: unit-reports
          path: reports/

  api-tests:
    needs: commit-stage
    runs-on: ubuntu-latest
    timeout-minutes: 20
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_PASSWORD: ci-only-password   # throwaway container, not a real secret
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    env:
      DATABASE_URL: postgres://postgres:ci-only-password@localhost:5432/postgres
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: 24
          cache: npm
      - run: npm ci
      - run: npm run db:migrate
      - run: npm run db:seed            # synthetic test data only
      - run: npm run test:api           # writes reports/junit-api.xml
      - uses: actions/upload-artifact@v7
        if: always()
        with:
          name: api-reports
          path: reports/

  e2e:
    needs: api-tests
    runs-on: ubuntu-latest
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        shard: [1, 2, 3, 4]
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: 24
          cache: npm
      - run: npm ci
      - run: npx playwright install --with-deps
      - run: npx playwright test --shard=${{ matrix.shard }}/4   # config starts the app
      - uses: actions/upload-artifact@v7
        if: always()
        with:
          name: e2e-results-${{ matrix.shard }}
          path: |
            playwright-report/
            test-results/

  deploy-staging:
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    needs: e2e
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - uses: actions/checkout@v7
      - run: ./scripts/deploy.sh staging
        env:
          DEPLOY_TOKEN: ${{ secrets.STAGING_DEPLOY_TOKEN }}
      - run: ./scripts/smoke.sh https://staging.example.com

جرّبها: منسّق YAML جرّبها: مولّد تعابير cron جرّبها: شارح تعابير cron

بوابات الجودة: معايير تستطيع إيقاف التغيير

بوابة الجودة (Quality gate) فحص بقاعدة نجاح/فشل يقرر ما إذا كان يجوز للتغيير الانتقال إلى المرحلة التالية — الدمج، أو النشر إلى staging، أو الترقية إلى الإنتاج. إنها الشكل الآلي لمعايير الخروج. وتكون البوابة مفيدة حين تكون موضوعية، وسريعة التقييم، ومرتبطة بخطر حقيقي، ومطبّقة دون استثناءات؛ أما البوابة التي تُتجاوز بشكل روتيني فتعلّم الجميع تجاهلها.

احذر بوابات المظاهر (vanity gates). قاعدة مثل «يجب ألا تقل تغطية الأسطر عن 80%» سهلة القياس وسهلة الإرضاء باختبارات تنفّذ الكود دون أن تتحقق من شيء مفيد. التغطية مفيدة كاتجاه وكوسيلة لإيجاد الكود غير المختبَر؛ أما كعتبة خام بلا سياق فتكافئ السلوك الخاطئ. والصيغة الأنفع هي تغطية الأسطر المتغيرة، تُراجع مع الاختبارات نفسها. وينطبق الأمر نفسه على «عدد الاختبارات» أو «نسبة نجاح 100% بعد إعادة المحاولة»: فهي تصف النشاط لا المخاطر.

  • جميع الفحوص المطلوبة خضراء: البناء والتدقيق وفحص الأنواع واختبارات الوحدة وAPI والاختبار الشامل — دون تخطّي أي اختبار خارج قائمة الحجر.
  • لا ثغرات جديدة حرجة أو عالية في الاعتماديات أو التحليل الساكن، أو استثناء مسجّل ومحدود المدة.
  • عقد API لم يتغير، أو التغيير متوافق مع الإصدارات السابقة (لا حقول محذوفة ولا مدخلات إلزامية جديدة) ما لم يكن ذا إصدار جديد.
  • دخان الأداء ضمن العتبات، مثلاً زمن استجابة p95 أقل من 400 ms ومعدل خطأ أقل من 1% عند حمل الدخان، مقارنةً بآخر خط أساس من الفرع الرئيسي.
  • ترحيلات قاعدة البيانات طُبّقت بنظافة على نسخة من المخطط الحالي، ومع خطة تراجع أو إصلاح أمامي مختبَرة حيث تتطلب العملية ذلك.
  • للترقية إلى الإنتاج: اجتياز دخان ما بعد النشر على staging وعدم وجود عيوب حاجبة مفتوحة على الإصدار.

تقارير الاختبار والمخرجات

نتيجة خط الأنابيب مفيدة بقدر ما يتركه خلفه. صيغة JUnit XML هي صيغة التبادل الشائعة لنتائج الاختبار: معظم مشغّلات الاختبار تستطيع كتابتها ومعظم أنظمة CI تستطيع قراءتها. وهي صيغة متعارف عليها فعلياً لا معيار رسمي، لذا تختلف السمات قليلاً بين الأدوات، لكن البنية الأساسية — حزم اختبار تحتوي حالات اختبار، لكل منها عنصر اختياري للإخفاق أو الخطأ أو التخطي، ومدة — مدعومة على نطاق واسع. فمثلاً يقرؤها GitLab عبر `artifacts:reports:junit` ويعرض الإخفاقات الجديدة والمُصلحة في طلب الدمج؛ وينشرها Jenkins كنتائج اختبار مع سجل تاريخي لكل اختبار.

وإلى جانب ملخص النجاح/الفشل، احتفظ بالمخرجات (artifacts) التي يحتاجها شخص لتشخيص الإخفاق دون إعادة التشغيل: سجلات التطبيق ومشغّل الاختبار، ولقطات الشاشة والفيديو لإخفاقات الواجهة، والتتبعات (trace في Playwright يسجّل الإجراءات والشبكة ولقطات DOM ويمكن فتحه بعد التشغيل)، والتقاطات طلبات HTTP واستجاباتها لإخفاقات API، وتقارير التغطية. حدّد فترة احتفاظ تكفي للمقارنة مع التشغيلات السابقة دون تراكم لا نهائي، وتأكد أنها لا تحتوي بيانات شخصية حقيقية أو أسراراً.

<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="3" failures="1" skipped="1" time="4.21">
  <testsuite name="orders-api" tests="3" failures="1" skipped="1" time="4.21">
    <testcase classname="orders.create" name="returns 201 for a valid order" time="0.84"/>
    <testcase classname="orders.create" name="rejects a negative quantity with 400" time="0.31">
      <failure message="expected status 400, received 500">AssertionError: expected 400, received 500
    at tests/orders.spec.ts:42</failure>
    </testcase>
    <testcase classname="orders.refund" name="refunds a captured payment" time="0">
      <skipped message="quarantined: FLAKY-112"/>
    </testcase>
  </testsuite>
</testsuites>

البيئات وبيانات الاختبار والأسرار

تحتاج اختبارات خط الأنابيب إلى مكان تعمل فيه. البيئات المؤقتة (Ephemeral environments) — تُنشأ لتشغيل واحد أو لطلب دمج واحد وتُدمَّر بعده — تمنح كل تغيير بنية نظيفة ومعزولة: حاويات خدمات لقواعد البيانات والطوابير، أو نشر معاينة قصير العمر لكل فرع. وهي تزيل سبباً رئيسياً للإخفاقات الكاذبة: تداخل الاختبارات عبر بيانات مشتركة. وما زالت البيئات المشتركة طويلة العمر (staging يحاكي الإنتاج) لازمة للتكامل مع أطراف ثالثة حقيقية ولتجربة الإصدار، لكنها تنحرف، لذا افحص إصداراتها وإعداداتها ضمن خط الأنابيب.

ينبغي أن ينشئ خط الأنابيب بيانات الاختبار بنفسه: الترحيلات تبني المخطط، وسكربتات البذر تحمّل خط أساس اصطناعياً معروفاً، وكل اختبار ينشئ السجلات المحددة التي يحتاجها بمعرّفات فريدة حتى لا تتصادم التشغيلات المتوازية. لا تنسخ أبداً بيانات شخصية من الإنتاج إلى CI. أما الأسرار — مفاتيح API ورموز النشر وكلمات مرور قواعد بيانات البيئات المشتركة — فمكانها مخزن الأسرار في منصة CI أو خزنة خارجية، محصورة في البيئات التي تحتاجها، ومحجوبة في السجلات، ومدوَّرة دورياً. وفي GitHub Actions لا تتلقى مسارات العمل التي تطلقها طلبات الدمج من المستودعات المتفرعة (forks) أسرار المستودع افتراضياً، وهذه ميزة أمان يجب الإبقاء عليها لا مشكلة يُلتف عليها.

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

جرّبها: مصنع بيانات الاختبار

التنفيذ المتوازي والتقسيم

حين تتجاوز الحزمة ميزانيتها الزمنية، شغّلها بالتوازي. داخل جهاز واحد تستخدم المشغّلات عدة عمّال (workers)؛ وعبر الأجهزة تُقسَّم الحزمة إلى أجزاء (sharding)، يشغّل كل جزء مجموعة فرعية على مشغّله الخاص، كما في المثال أعلاه. يقلّص التقسيم الزمن الفعلي بما يتناسب تقريباً مع عدد الأجزاء إن كانت متوازنة؛ والتقسيم حسب مدة الاختبار المسجّلة يوازن أفضل من التقسيم حسب عدد الملفات.

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

التعامل مع الاختبارات المتذبذبة في خط الأنابيب

الاختبار المتذبذب (Flaky test) ينجح ويفشل على الكود نفسه. وفي خط الأنابيب يُحدث ضرراً مزدوجاً: يحجب التغييرات السليمة، ويعلّم الناس الضغط على «إعادة التشغيل» حتى يخضرّ، وبعدها تُتجاهل الإخفاقات الحقيقية أيضاً. يصف مقال مارتن فاولر عن اللاحتمية الحجرَ (quarantine) كاستجابة: انقل الاختبار المتذبذب من الحزمة الحاكمة إلى مجموعة منفصلة ما زالت تعمل، ليبقى خط الأنابيب جديراً بالثقة ريثما يُصلح الاختبار. الأسباب والإصلاحات يغطيها دليل الاختبارات المتذبذبة؛ أما خط الأنابيب فيحتاج إلى سياسة.

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

تحليل إخفاقات خط الأنابيب: مسار للفرز

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

يطرح مسار الفرز أدناه خمسة أسئلة بالترتيب. (1) هل فشلت المهمة قبل تشغيل أي اختبار (تثبيت الاعتماديات، أو البناء، أو سحب الصورة، أو فقدان المشغّل)؟ إن كان كذلك فهي مشكلة في خط الأنابيب أو البنية التحتية يملكها فريق المنصة: أصلحها ثم أعد التشغيل. (2) هل فشلت أثناء الإعداد (قاعدة بيانات غير جاهزة، أو خطأ ترحيل، أو خدمة غير سليمة، أو سر منتهي الصلاحية)؟ إن كان كذلك فهي مشكلة بيئة: أصلح البيئة ولا تلمس الاختبارات. (3) أعد تشغيل الاختبارات الفاشلة مرة واحدة على الإيداع نفسه: إن نجحت فهو اختبار مرشح للتذبذب — سجّله (معرّف الاختبار، والإيداع، والخطأ، ورابط التشغيل)، وافتح تذكرته أو حدّثها، واحجره إن تكرر؛ والإعادة الخضراء لا تثبت أن التغيير آمن. وإن فشلت مجدداً فالإخفاق حتمي، فانتقل إلى السؤال التالي. (4) هل يفشل الاختبار نفسه على الفرع الرئيسي دون هذا التغيير؟ إن كان كذلك فهو كسر سابق أو انحراف في البيئة: أبلغ مالك الفرع الرئيسي؛ وإلا فالتغيير هو السبب، فانتقل إلى السؤال الأخير. (5) هل سلوك المنتج خاطئ، أم أن توقع الاختبار قديم؟ إن كان المنتج خاطئاً فهو عيب في المنتج: تقرير خطأ ويبقى الدمج محجوباً؛ وإن كان السلوك الجديد مقصوداً فهو تحديث للاختبار ضمن التغيير نفسه، يُراجع كما يُراجع الكود.

خمسة أسئلة بالترتيب تصنّف خط الأنابيب الأحمر: البنية التحتية والبيئة أولاً، ثم التذبذب والكسر السابق على الفرع الرئيسي، وبعدها فقط عيب في المنتج أو اختبار قديم.
سؤال 1: هل فشلت المهمة قبل تشغيل أي اختبار؟تثبيت الاعتماديات، أو البناء، أو سحب الصورة، أو فقدان المشغّل
  • الإجابة: نعم

    النتيجة: مشكلة في خط الأنابيب أو البنية التحتيةيملكها فريق المنصة: أصلحها ثم أعد التشغيل.
  • الإجابة: لا

    سؤال 2: هل فشلت أثناء الإعداد؟قاعدة بيانات غير جاهزة، أو خطأ ترحيل، أو خدمة غير سليمة، أو سر منتهي الصلاحية
    • الإجابة: نعم

      النتيجة: مشكلة بيئةأصلح البيئة ولا تلمس الاختبارات.
    • الإجابة: لا

      سؤال 3: أعد تشغيل الاختبارات الفاشلة مرة واحدة على الإيداع نفسه: هل نجحت الآن؟
      • الإجابة: نعم

        النتيجة: اختبار مرشح للتذبذبسجّله، وافتح تذكرته أو حدّثها، واحجره إن تكرر. والإعادة الخضراء لا تثبت أن التغيير آمن.
      • الإجابة: لا: الإخفاق حتمي

        سؤال 4: هل يفشل الاختبار نفسه على الفرع الرئيسي دون هذا التغيير؟
        • الإجابة: نعم

          النتيجة: كسر سابق أو انحراف في البيئةأبلغ مالك الفرع الرئيسي.
        • الإجابة: لا: التغيير هو السبب

          سؤال 5: هل سلوك المنتج خاطئ، أم أن توقع الاختبار قديم؟
          • الإجابة: المنتج خاطئ

            النتيجة: عيب في المنتجتقرير خطأ، ويبقى الدمج محجوباً.
          • الإجابة: السلوك الجديد مقصود

            النتيجة: تحديث للاختبار ضمن التغيير نفسهيُراجع كما يُراجع الكود.
  • اقرأ الخطأ الأول لا الأخير؛ فالإخفاقات اللاحقة كثيراً ما تكون نتائج له.
  • قارن بآخر تشغيل أخضر للمهمة نفسها: اعتماديات متغيرة، أو صورة مشغّل، أو بيانات، أو إعدادات.
  • احتفظ بسجل إخفاقات يصنّف كل بناء أحمر؛ وخلال شهر يُظهر ما إذا كان خط الأنابيب يعاني أساساً من العيوب أو التذبذب أو البيئات.
  • عيوب المنتج التي يكتشفها خط الأنابيب تحصل على تقرير خطأ عادي يُرفق به الاختبار الفاشل والإيداع والمخرجات.
النسخة النصية
Pipeline failed
|
|-- 1. Did the job fail before any test ran? (dependency install, build, image pull, runner lost)
|      yes -> PIPELINE / INFRASTRUCTURE problem. Owner: platform. Fix, then re-run.
|
|-- 2. Did it fail during setup? (DB not ready, migration error, service unhealthy, expired secret)
|      yes -> ENVIRONMENT problem. Fix the environment; do not touch the tests.
|
|-- 3. Re-run the failed tests once on the SAME commit. Do they pass now?
|      yes -> FLAKY candidate. Log it (test id, commit, error, run link), open or update its ticket,
|             quarantine if it repeats. The change is not proven safe by the green re-run.
|      no  -> deterministic failure, continue.
|
|-- 4. Does the same test fail on main without this change?
|      yes -> PRE-EXISTING break or environment drift. Notify whoever owns main.
|      no  -> caused by this change, continue.
|
`-- 5. Is the product behaviour wrong, or is the test's expectation out of date?
       product wrong       -> PRODUCT DEFECT. Bug report, merge blocked.
       intended new change -> TEST UPDATE in the same change, reviewed like code.

جرّبها: محلّل رسائل الأخطاء بالذكاء الاصطناعي

ماذا يفعل المختبِر في CI/CD

في الفرق التي تملك خط أنابيب، يقضي المختبِرون وقتاً أقل في تنفيذ الفحوص المكتوبة يدوياً، ووقتاً أكثر في تقرير ما يفحصه خط الأنابيب، والحفاظ على جدارته بالثقة، واختبار ما لا يستطيع فحصه. العمل أدناه ملخص عملي؛ أما أي الاختبارات تُؤتمت وعلى أي مستوى فيغطيه دليل الاختبار اليدوي مقابل الآلي، والمقاييس التي تُظهر ما إذا كان التسليم بصحة جيدة — نسبة فشل التغييرات وزمن التعافي من النشر الفاشل، ضمن مقاييس DORA — تستحق المراجعة مع الفريق في كل إصدار.

  • اربط المخاطر بالمراحل: أي فحص، في أي مرحلة، يحمي من أي إخفاق.
  • صمّم حزمة الانحدار وراجعها، بما في ذلك قواعد اختيارها لطلبات الدمج مقابل التشغيلات الليلية.
  • عرّف بوابات الجودة مع الفريق واعترض على بوابات المظاهر.
  • امتلك سياسة الاختبارات المتذبذبة وسجل الإخفاقات؛ وافرز البناءات الحمراء مع المطورين.
  • اكتب فحوص الدخان بعد النشر واتفق على معايير التراجع قبل الإصدار.
  • احتفظ بالاختبار الاستكشافي للميزات الجديدة — فلا خط أنابيب يغني عن شخص يبحث عمّا لم يفكر أحد في أتمتته.

جرّبها: مولّد سيناريوهات الانحدار جرّبها: فاحص صحة API

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

ما الفرق بين التسليم المستمر والنشر المستمر؟

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

أي الاختبارات يجب أن تعمل عند كل إيداع؟

الفحوص السريعة والحتمية: التحليل الساكن، واختبارات الوحدة، واختبارات المكوّنات، وعادةً مجموعة مركّزة من اختبارات API. وينبغي أن تنتهي معاً خلال بضع دقائق. أما الحزم الأطول — الاختبار الشامل الكامل، واختبارات الحمل الطويلة، وفحوص الأمان الكاملة — فمكانها المراحل اللاحقة أو التشغيلات المجدولة.

هل عتبة تغطية الكود بوابة جودة جيدة؟

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

هل ينبغي أن يعيد خط الأنابيب محاولة الاختبارات الفاشلة تلقائياً؟

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

ما JUnit XML ولماذا يهم؟

صيغة XML لنتائج الاختبار — الحزم وحالات الاختبار والإخفاقات والتخطيات والمدد — تستطيع معظم مشغّلات الاختبار كتابتها ومعظم أنظمة CI قراءتها. واستخدامها يتيح لخط الأنابيب عرض الإخفاقات في طلبات الدمج، وتتبّع تاريخ كل اختبار، ودمج نتائج الأجزاء المتوازية.

كيف أعرف ما إذا كان الإخفاق عيباً أم مشكلة بيئة؟

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

هل ما زال المختبِرون يختبرون يدوياً في فريق CI/CD؟

نعم، لكن بطريقة مختلفة. ينتقل الانحدار المكتوب إلى خط الأنابيب؛ ويقضي المختبِرون وقتهم في الاختبار الاستكشافي للميزات الجديدة، وتحليل المخاطر، وتصميم الاختبارات، وتعريف البوابات، وفرز الإخفاقات.

المراجع

  • Continuous Integration (Martin Fowler)martinfowler.com · 2024الوصف الأكثر استشهاداً للتكامل المستمر: ادمج كثيراً، واجعل البناء يختبر نفسه وسريعاً، وأصلح البناء المكسور فوراً.
  • ISTQB Certified Tester Foundation Level (CTFL) v4.0ISTQB · 2023المنهج التأسيسي لاختبار البرمجيات: مستويات الاختبار وأنواعه وتقنيات تصميم الاختبارات وإدارة الاختبار والأدوات.
  • GitHub Actions documentationGitHubكيف تُعرَّف مسارات العمل والمهام والمشغّلات والمخرجات في GitHub Actions — حيث تعمل الاختبارات الآلية عند كل دفع أو طلب دمج.
  • GitLab CI/CDGitLabكيف تُعرَّف خطوط الأنابيب والمهام والمخرجات — حيث تعمل حزمة الانحدار الآلية عند كل تغيير.
  • Unit test reports — GitLab CI/CDGitLabنشر نتائج JUnit XML كمخرجات لخط الأنابيب لتظهر الاختبارات الفاشلة في طلب الدمج ويمكن مقارنتها بين التشغيلات.
  • Pipeline — Jenkins User HandbookJenkins Projectخطوط Jenkins المعرّفة ككود في ملف Jenkinsfile: المراحل والخطوات والتنفيذ المتوازي ونشر نتائج الاختبار.
  • Eradicating Non-Determinism in Tests (Martin Fowler)martinfowler.com · 2011لماذا تُفقد الاختبارات المتذبذبة الحزمةَ قيمتها، وأسبابها الشائعة (العزل وعدم التزامن والخدمات البعيدة والوقت وتسرّب الموارد)، والحجر كاستجابة.
  • DORA's software delivery performance metricsDORA (Google Cloud)مقاييس DORA للتسليم — زمن تنفيذ التغيير وتكرار النشر وزمن التعافي من النشر الفاشل ونسبة فشل التغييرات وما يتصل بها — مجمّعة حسب الإنتاجية وعدم الاستقرار.

تمرين عملي

راجع مسودة خط أنابيب وافرز تشغيلاته الحمراء

المطلوب

أنت المختبِر الوحيد في فريق من ستة مطورين يبني منصة لحجز تذاكر السينما (مثال خيالي): تطبيق ويب وواجهة REST API في مستودع واحد، مبنيان بـ Node.js وPostgreSQL، والتكامل المستمر (CI) على GitHub Actions. في هذا السبرنت سيصبح خط الأنابيب (pipeline) بوابة الدمج لكل طلب دمج. كتب أحد المطورين المسودة أدناه — وهي تعمل الآن لكنها لا تمنع أي دمج بعد — وطلب منك مراجعتها قبل أن تصبح كذلك. وتعرض المادة أيضاً التشغيلات الحمراء الخمسة للأسبوع الماضي، التي لم يصنّفها أحد بعد.

راجع المسودة مقابل الدليل: ترتيب المراحل وميزانياتها الزمنية، وسياسة الاختبارات المتذبذبة، وبيانات الاختبار والأسرار، والتقارير والمهل، وبوابة التغطية المقترحة، والجدولة الليلية. اكتب بوابة الدمج التي تقترحها، ثم افرز التشغيلات الحمراء الخمسة بمسار الأسئلة الخمسة من الدليل. اعمل على الورق؛ ويساعدك محوّل المناطق الزمنية في سطر واحد من المسودة. خصّص لذلك ⁦30–45⁩ دقيقة.

المادة
منصة لحجز تذاكر السينما (مثال خيالي) - تطبيق ويب وواجهة REST API في مستودع واحد
الفريق: 6 مطورين ومختبِر واحد (أنت). البناء: Node.js وPostgreSQL. CI: GitHub Actions.
هدف هذا السبرنت: أن يصبح خط الأنابيب بوابة الدمج لكل طلب دمج.

مسودة خط الأنابيب (كتبها مطوّر). تعمل الآن، لكنها لا تمنع أي دمج بعد.
المهام بترتيب تشغيلها اليوم؛ وسطر retries في J1 جديد في هذه المسودة.
  J1  e2e            Playwright، 310 اختبارات متصفح، نحو 38 دقيقة، عند كل دفع.
                     جديد في المسودة: retries: 3؛ والمهمة خضراء إذا نجح كل اختبار
                     في محاولة ما.
  J2  unit           2,400 اختبار وحدة، نحو 3 دقائق.
  J3  lint-types     eslint وtsc، نحو دقيقة واحدة.
  J4  api            140 اختباراً لـ API، نحو 9 دقائق، مقابل قاعدة البيانات المشتركة
                     «qa-shared» التي تُستعاد كل ليلة من نسخة (dump) لقاعدة الإنتاج.
  J5  coverage-gate  يفشل إذا قلّت تغطية الأسطر عن 80%.
  J6  deploy-staging على الفرع الرئيسي فقط. يُقرأ DEPLOY_TOKEN من ci/deploy.env،
                     وهو ملف مودَع في المستودع. لا يعمل أي فحص بعد النشر.
  J7  nightly        الانحدار الكامل واختبار حمل لمدة 20 دقيقة؛ cron "0 2 * * *"،
                     والمقصود أن يعمل في 02:00 بتوقيت الرياض. تذهب النتائج إلى قناة
                     محادثة لم يُكلَّف أحد بقراءتها.
  التقارير           يُرفع تقرير Playwright بصيغة HTML والتتبعات فقط عند نجاح المهمة.
                     ولا مهلة (timeout) لأي مهمة.

التشغيلات الحمراء في الأسبوع الماضي (من R1 إلى R5)
  R1  طلب الدمج 741، مهمة unit: يفشل "npm ci" بعد 40 ثانية بالخطأ
      ENOTFOUND registry.npmjs.org. لم يعمل أي اختبار.
  R2  طلب الدمج 744، مهمة api: إخفاق واحد، seats.hold
      "returns 409 when the seat is already held": المتوقع 409 والفعلي 200.
      إعادة التشغيل على الإيداع نفسه: يفشل مجدداً. الاختبار نفسه على الفرع الرئيسي:
      ينجح. يغيّر طلب الدمج خدمة حجز المقاعد.
  R3  طلب الدمج 745، مهمة e2e: إخفاق واحد، checkout "shows the order summary":
      انتهت المهلة بانتظار لوحة الملخص. إعادة التشغيل على الإيداع نفسه: ينجح.
      المرة الرابعة هذا الشهر لهذا الاختبار، في طلبات دمج غير مترابطة.
  R4  الفرع الرئيسي، مهمة api: تنتهي مهلة خطوة الإعداد "wait for database" بعد 60 ثانية:
      connect ETIMEDOUT qa-shared:5432. لم يعمل أي اختبار API.
  R5  طلب الدمج 749، مهمة api: إخفاق واحد، pricing "applies the 10% student discount":
      المتوقع 45.00 والفعلي 42.50 (سعر التذكرة 50.00 ريال). إعادة التشغيل: يفشل مجدداً.
      الفرع الرئيسي: ينجح. ينفّذ طلب الدمج 749 التغيير المعتمد TK-311
      «يصبح خصم الطلاب 15%».
الخطوات
  1. رتّب المهام بالترتيب الذي يوصي به الدليل، وأعطِ كل مرحلة ميزانية زمنية، وحدّد أي المهام تحكم طلب الدمج وأيها ينتمي إلى التشغيل الليلي.
  2. مرّ على المسودة سطراً سطراً واكتب كل ممارسة تخالف الدليل مع إصلاحها (إعادة المحاولة، وبيانات الاختبار، وبوابة التغطية، والسر، والجدولة، والتقارير، والمهل).
  3. اكتب بوابة الدمج لطلب الدمج في قائمة قصيرة من قواعد نجاح/فشل موضوعية.
  4. صنّف التشغيلات من R1 إلى R5 بمسار الفرز ذي الأسئلة الخمسة: السؤال الذي يحسم التصنيف، والتصنيف، والمالك، والإجراء التالي.
  5. املأ سجل الإخفاقات للأسبوع (كم حالة من كل صنف)، وسمِّ شيئاً واحداً لا يستطيع هذا الخط فحصه وستختبره أنت.
إظهار الإجابة النموذجية
الإجابة النموذجية

الترتيب والميزانيات. تشغّل المسودة أبطأ مهمة وأكثرها اعتماداً على البيئة أولاً، وأرخص الفحوص أخيراً، فخطأ الأنواع الذي يكشفه tsc في دقيقة لا يظهر إلا بعد ⁦38⁩ دقيقة من اختبارات المتصفح. اعكس الترتيب. مرحلة الإيداع (Commit stage)، عند كل دفع وكل طلب دمج، بميزانية نحو ⁦5⁩ دقائق: J3 lint-types (دقيقة واحدة) ثم J2 unit (⁦3⁩ دقائق)، مع فحص الاعتماديات والأسرار الذي تخلو منه المسودة. مرحلة API، بـ needs على مرحلة الإيداع، بميزانية نحو ⁦10⁩ دقائق: J4 مقابل حاوية خدمة (انظر أدناه). مرحلة الاختبار الشامل، بـ needs على مرحلة API: ليس ⁦310⁩ اختبارات عند كل دفع. أبقِ مجموعة صغيرة من رحلات المستخدم الحرجة حزمةً حاكمة — إيجاد عرض، وحجز مقعد، والدفع، واستلام التذكرة — مقسّمة إلى أجزاء (shards) متوازنة حسب المدة المسجّلة، مع fail-fast: false ودمج تقارير الأجزاء في نتيجة واحدة، لتنتهي خلال نحو ⁦10⁩ دقائق؛ وتنتقل بقية اختبارات المتصفح إلى التشغيل الليلي. وتعمل J6 deploy-staging على الفرع الرئيسي فقط بعد الاختبار الشامل، ويتبعها سكربت دخان وفحوص صحة على staging، وهذا ما تخلو منه المسودة. هكذا يحصل طلب الدمج على أول جواب خلال دقائق وعلى جوابه الكامل خلال نحو ⁦25⁩ دقيقة، بدلاً من انتظار ⁦38⁩ دقيقة قبل أن يبدأ أول اختبار وحدة.

سطر retries: 3 الجديد في J1، مع مهمة خضراء إذا نجحت أي محاولة، هو عكس سياسة الدليل: إعادة محاولة آلية واحدة على الأكثر، والاختبار الذي نجح فقط عند إعادة المحاولة يُبلَّغ عنه كمتذبذب لا كناجح، ولا تُعاد مهمة كاملة بصمت أبداً. ولو طُبّق هذا السطر لنجح اختبار checkout في R3 على الأرجح عند إعادة المحاولة في المرات الأربع ولما لاحظه أحد، وكذلك حالة تسابق حقيقية في حجز المقاعد، وهي بالضبط نوع العيوب المتقطعة الذي لا يحتمله نظام تذاكر. اضبط إعادة محاولة واحدة، واجعل التقرير يعرض النجاح عند إعادة المحاولة تذبذباً، وسجّل كل حالة بمعرّف الاختبار والإيداع والخطأ ورابط التشغيل.

تخالف J4 قاعدتين معاً. فقاعدة البيانات المشتركة «qa-shared» تُستعاد من نسخة لقاعدة الإنتاج: البيانات الشخصية من الإنتاج (أسماء العملاء وأرقام هواتفهم ومراجع الدفع) لا مكان لها في CI أبداً، والقاعدة المشتركة تجعل التشغيلات المتوازية وطلبات الدمج تتداخل عبر صفوف مشتركة، وهو ما يسمّيه الدليل سبباً رئيسياً للإخفاقات الكاذبة. استبدلها بحاوية خدمة PostgreSQL لكل تشغيل: المخطط من الترحيلات، وخط أساس اصطناعي من سكربتات البذر، وسجلات كل اختبار بمعرّفات فريدة. وأبلغ المسؤول عن حماية البيانات في شركتك بأمر هذه النسخة، فقد توجد نسخ منها على المشغّلات وفي المخرجات. وتحتفظ J6 بـ DEPLOY_TOKEN في ci/deploy.env داخل المستودع: الأسرار لا تكون في المستودع أبداً، ولا تُطبع، ولا تدخل المخرجات. انقله إلى مخزن الأسرار في المنصة محصوراً في بيئة staging، وعامل الرمز المودَع على أنه مكشوف: ألغِه وأصدر رمزاً جديداً، فتاريخ المستودع ما زال يحوي القيمة القديمة.

J5، أي فشل البناء إذا قلّت تغطية الأسطر عن ⁦80%⁩، بوابة مظاهر (vanity gate): سهلة الإرضاء باختبارات تنفّذ الكود دون أن تتحقق من شيء، وصامتة عن المخاطر. أبقِ التغطية اتجاهاً ووسيلة لإيجاد الكود غير المختبَر؛ وإن أراد الفريق بوابة، فاستخدم تغطية الأسطر المتغيرة مع مراجعة الاختبارات نفسها. ورفع التقارير عند النجاح فقط عكس ما يوصي به الدليل: ارفعها بـ if: always()، لأن الإخفاق بلا أدلته هو الأغلى تحقيقاً — التتبعات ولقطات الشاشة وسجلات المشغّل والتقاطات HTTP — مع فترة احتفاظ ودون بيانات شخصية فيها. وتحتاج كل مهمة إلى timeout-minutes ليصبح الاختبار المعلّق إخفاقاً ظاهراً بدلاً من مهمة تنتظر ساعات. ولـ J7 مشكلتان: جداول cron في GitHub Actions تعمل بتوقيت UTC ما لم تحدد الجدولة منطقة زمنية، والمسودة لا تحدد أي منطقة، فـ 0 2 * * * يعمل في ⁦02:00⁩ UTC، أي ⁦05:00⁩ بتوقيت الرياض (⁦UTC+3⁩ بلا توقيت صيفي)؛ ولتشغيله في ⁦02:00⁩ بتوقيت الرياض اكتب 0 23 * * *، أي ⁦23:00⁩ UTC من اليوم السابق. والمرحلة المجدولة يجب أن تُبلغ مالكاً يتصرف حيال الإخفاقات: سمِّ واحداً، ودوّر المناوبة، وحوّل كل إخفاق ليلي إلى تذكرة أو بند فرز بدلاً من رسالة لا يقرؤها أحد.

بوابة الدمج لطلب الدمج، قواعد نجاح/فشل موضوعية على آخر إيداع: (1) التدقيق وفحص الأنواع واختبارات الوحدة وAPI ورحلات الاختبار الشامل الحرجة خضراء، بإعادة محاولة آلية واحدة على الأكثر (والنجاح عند إعادة المحاولة يُبلَّغ عنه ويُسجَّل تذبذباً) ودون تخطّي أي اختبار خارج قائمة الحجر؛ (2) لا ثغرة جديدة حرجة أو عالية في الاعتماديات أو التحليل الساكن، أو استثناء مسجّل ومحدود المدة؛ (3) عقد API لم يتغير أو التغيير متوافق مع الإصدارات السابقة — لا حقول محذوفة ولا مدخلات إلزامية جديدة — ما لم يكن ذا إصدار جديد؛ (4) تُطبَّق ترحيلات قاعدة البيانات في طلب الدمج بنظافة على قاعدة البيانات الجديدة في مرحلة API. وتُعرض تغطية الأسطر المتغيرة على المراجع لكنها ليست عتبة. والحزمة الليلية ليست جزءاً من البوابة: فهي شبكة الأمان ويجب أن تكون خضراء للمرشح للإصدار. وتُسجَّل الاستثناءات بسبب وتاريخ انتهاء؛ فالبوابة التي تُتجاوز بشكل روتيني تعلّم الجميع تجاهلها.

R1 — السؤال الأول يحسمه: فشلت المهمة قبل تشغيل أي اختبار، أثناء npm ci؛ وENOTFOUND يعني أن المشغّل لم يستطع تحليل اسم نطاق سجل الحزم (DNS). مشكلة في خط الأنابيب أو البنية التحتية. المالك: من يصون المشغّلات وخط الأنابيب (دور المنصة؛ وفي هذا الفريق غالباً المطوّر الذي كتب المسودة). أعد التشغيل حين يعود تحليل الأسماء إلى العمل؛ وإن تكرر فليفحص هذا المالك شبكة المشغّل وDNS. لا شيء يتغير في الاختبارات أو المنتج. R4 — السؤال الأول يخص خطوات خط الأنابيب نفسه (التثبيت والبناء والصورة والمشغّل)، وقد نجحت؛ والسؤال الثاني يحسمه: فشلت المهمة أثناء الإعداد وهي تنتظر قاعدة البيانات المشتركة qa-shared، ولم يعمل أي اختبار. مشكلة بيئة: لا تلمس الاختبارات. المالك: من يدير qa-shared؛ اعرف هل كانت متوقفة أو يُعاد تشغيلها أو ما زالت قيد الاستعادة، وقارن بآخر تشغيل أخضر للمهمة نفسها، وأعد التشغيل حين تستجيب. ولأن هذا على الفرع الرئيسي، أبلغ الفريق أن حالة الفرع الرئيسي مجهولة حتى يأتي تشغيل أخضر. وR4 حجة إضافية لحاوية الخدمة لكل تشغيل المقترحة لـ J4.

R2 — السؤالان الأول والثاني: لا، فالاختبارات عملت. السؤال الثالث: إعادة التشغيل على الإيداع نفسه تفشل مجدداً، فالإخفاق حتمي. السؤال الرابع: الاختبار ينجح على الفرع الرئيسي، فهذا التغيير هو السبب. السؤال الخامس: سلوك المنتج خاطئ. فالمقعد المحجوز مسبقاً يجب أن يُرفض بـ 409؛ و200 تعني أن عميلين يستطيعان حجز المقعد نفسه، وطلب الدمج يغيّر خدمة حجز المقاعد بالذات. عيب في المنتج، والمالك: صاحب طلب الدمج 744. اكتب تقرير خطأ مع الاختبار الفاشل والإيداع ورابط التشغيل والطلب الذي أعاد 200 مع استجابته، مع اقتراح الخطورة «حرج» (Critical) لأنه يؤدي إلى حجز مزدوج؛ ويبقى الدمج محجوباً حتى يُصلَح وينجح الاختبار. والاختبار ليس متقادماً: فلم يتغير أي متطلب.

R3 — السؤال الثالث: إعادة التشغيل على الإيداع نفسه تنجح، فهو مرشح للتذبذب، والتاريخ يحسم الأمر: الإخفاق الرابع هذا الشهر في طلبات دمج غير مترابطة. سجّله (معرّف الاختبار، والإيداع، والخطأ، ورابط التشغيل)، وحدّث تذكرته، واحجره: يواصل العمل والإبلاغ، ويتوقف عن الحكم، ويحصل على مالك (من يملك اختبارات إتمام الشراء) وموعد نهائي لإصلاحه أو حذفه. والإعادة الخضراء لا تثبت أن طلب الدمج 745 آمن، والتشغيل الفاشل لم يترك تتبعاً يُفحص، لأن التقارير والتتبعات تُرفع عند النجاح فقط — وهذا سبب إضافي لـ if: always(). وبعد إصلاح ذلك افتح تتبع الإخفاق التالي لترى هل ظهرت لوحة الملخص متأخرة أم انتظر الاختبار العنصر الخطأ، وهل يمكن أن يكون إتمام الشراء نفسه بطيئاً على المستخدمين.

R5 — السؤال الثالث: حتمي؛ والرابع: ينجح على الفرع الرئيسي، فالتغيير هو السبب؛ والخامس: السلوك الجديد هو التغيير المقصود والمعتمد TK-311، فتوقع الاختبار هو المتقادم لا المنتج. تحقق من الحساب: خصم ⁦15%⁩ من ⁦50.00⁩ ريال يعطي ⁦42.50⁩، وهو ما أعاده المنتج. المالك: صاحب طلب الدمج 749. حدّث الاختبار في طلب الدمج نفسه — العنوان "applies the 15% student discount" والمتوقع ⁦42.50⁩ — وليُراجَع كما يُراجع الكود؛ ولا يُدمج طلب الدمج حتى يحوي هذا الإيداع. سجل الإخفاقات للأسبوع: بنية تحتية واحدة (R1)، وبيئة واحدة (R4)، وتذبذب واحد (R3)، وعيب منتج واحد (R2)، وتحديث اختبار واحد (R5)؛ وخلال شهر يُظهر هذا السجل هل يعاني خط الأنابيب أساساً من العيوب أو التذبذب أو البيئات. وما لا يستطيع خط الأنابيب فحصه بعد: الخصم الجديد في واجهة المستخدم وخريطة المقاعد كما يراها العميل، فالاختبار الاستكشافي للميزات الجديدة يبقى معك.

تقدّمك في هذا الموضوع

جزء من مسار تعلم ضمان الجودة

الأدوات المذكورة في هذا الدليل

افحص عدة نقاط نهاية لصحة API دفعة واحدة واحصل على الحالة وزمن الاستجابة وملخّص نجاح/فشل.

اختبار واجهات API

قِس زمن استجابة نقطة نهاية عبر عدة عيّنات: الحد الأدنى والأقصى والمتوسط والوسيط وp95.

الأداء

تنسيق YAML والتحقق من صحته بمسافات بادئة وعلامات اقتباس متسقة.

التنسيق

أنشئ تعابير cron بصرياً وعاين أوقات التشغيل التالية.

أدوات مساعدة

ترجم أي تعبير cron إلى لغة إنجليزية مبسّطة واعرض أوقات التشغيل القادمة.

أدوات مساعدة

اشرح تتبّعات المكدس (stack traces) ورسائل الأخطاء، وحدّد الأسباب الجذرية المحتملة وخطوات التصحيح التالية باستخدام الذكاء الاصطناعي من متقن.

تحليل الأخطاء ذكاء اصطناعي

مصنع متكامل لبيانات الاختبار الاصطناعية: مستخدمون وعملاء وشركات وعناوين وأرقام وتواريخ وسلاسل نصية بصيغة JSON أو CSV أو SQL أو XML.

بيانات الاختبار

كيف تساعدك متقن سوفت

أدلة أخرى

أدلة أخرى
تصميم الاختبارات

اختبار الدخان والسلامة والانحدار: مقارنة

مقارنة بين اختبار الدخان والسلامة والانحدار: النطاق والتوقيت والعمق والأتمتة، ولماذا مصطلح «السلامة» ملتبس، وكيف تختار اختبارات الانحدار.

وقت القراءة 8 دقائق
الأتمتة

اختبار التحقق من النشر

كيف تتحقق من النشر: خطة مكتوبة مسبقاً، واختبارات دخان بعد النشر، وفحوص اصطناعية، وإصدارات كناري، وأعلام الميزات، والإشارات، والتراجع.

وقت القراءة 10 دقائق
تصميم الاختبارات

الاختبار اليدوي مقابل الاختبار الآلي

مقارنة بين الاختبار اليدوي والآلي في التكلفة والسرعة وما يجده كل منهما وما يفوته والصيانة — مع قاعدة عملية لتقرير ما يُؤتمت وما يُترك للبشر.

وقت القراءة 6 دقائق
الأتمتة

الاختبارات المتذبذبة

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

وقت القراءة 9 دقائق
تصميم الاختبارات

ضمان جودة المنتج من البداية إلى النهاية

ما الذي يشمله ضمان الجودة الشامل — مراجعة المتطلبات وتصميم الاختبارات والاختبار الوظيفي واختبار الأداء والأمان وبوابات الإصدار والمقاييس — وكيف تنفّذه.

وقت القراءة 8 دقائق
تصميم الاختبارات

دورة حياة اختبار البرمجيات (STLC)

مراحل STLC واحدة تلو الأخرى — التحليل والتخطيط والتصميم والبيئة والتنفيذ والإغلاق — مقابل عملية الاختبار في ISTQB، مع معايير الدخول والخروج لكل مرحلة.

وقت القراءة 12 دقائق