مقارنة أساليب اختبار الواجهات البرمجية
يمكن اختبار الواجهة البرمجية بشخص يرسل الطلبات، وبنصوص برمجية تتحقق من الاستجابات، وبمقارنة كل استجابة بالعقد المنشور، وبالنيابة عن الواجهة بمحاكاة حتى يمكن اختبار مستهلكيها، وبتحميلها حتى تبطؤ أو تفشل. يجيب كل أسلوب عن سؤال مختلف، والفريق الذي يستخدم أسلوباً واحداً فقط — الأول عادة — يطلق منتجه والأسئلة الأربعة الأخرى بلا إجابة.
يضع هذا الدليل الأساليب الخمسة جنباً إلى جنب: ما يلتقطه كل منها وما يفوته وما يكلّفه وأي البروتوكولات تغيّر القواعد. ويختم بمزيج يناسب معظم المنتجات وأسباب الخروج عنه.
الأساليب الخمسة
- الطلبات الاستكشافية — يبني شخص الطلبات في عميل (Postman أو cURL أو أداة في المتصفح) ويقرأ الاستجابات ويحكم عليها. سريع البدء، يلتقط غير المتوقع، ولا يثبت شيئاً بعد انتهاء الجلسة.
- الاختبارات الوظيفية المكتوبة — كود يرسل الطلبات ويتحقق من الحالة والترويسات والجسم، ويعمل في CI. يثبت الأشياء نفسها كل مرة؛ ولا يجد إلا ما كُتب ليجده.
- اختبار العقد — تُفحص كل استجابة مقابل مواصفة الواجهة (مستند OpenAPI أو JSON Schema أو مخطط GraphQL)، فالحقل الذي يتغير نوعه أو يختفي يُفشل الاختبار دون أن يكتب أحد تأكيداً له.
- المحاكاة والافتراضية الخدمية — بديل يعيد استجابات مختارة حتى يمكن اختبار مستهلكي الواجهة قبل وجودها، وحتى يمكن إنتاج مسارات الخطأ (500 و429 والمهل والأجسام المشوهة) عند الطلب.
- اختبار الحمل والأداء — طلبات متزامنة بمجموعة بيانات واقعية لقياس زمن الاستجابة والإنتاجية ومعدل الخطأ تحت الحمل، بأدوات مثل JMeter أو k6.
جرّبها: منشئ طلبات API جرّبها: مختبِر REST API جرّبها: مدقّق استجابات API
ما يلتقطه كل أسلوب — وما يفوته
الأساليب ليست متنافسة؛ فهي تغطي فئات فشل مختلفة. يلتقط الاختبار الاستكشافي منطق العمل الخاطئ ورسائل الخطأ المربكة والسلوك غير الموثق، ويفوته الانحدار لأن شيئاً لا يعيد تشغيله. وتلتقط الاختبارات المكتوبة الانحدار في المسارات التي كُتبت لها ويفوتها كل شيء آخر. ويلتقط اختبار العقد التغييرات الكاسرة في شكل الواجهة — فئة العيوب التي تكسر تطبيق جوال في أيدي المستخدمين بالفعل — وتفوته القيم الخاطئة داخل شكل صحيح. وتتيح المحاكاة اختبار المستهلكين بمعزل وفرض مسارات الخطأ، ويفوتها السلوك الفعلي للواجهة الحقيقية، ولهذا يجب أن يربط عقد المحاكاة بالحقيقة. ويلتقط اختبار الحمل مشكلات السعة والتزامن ويفوته الوظيفي كلياً.
- منطق عمل خاطئ في نقطة نهاية جديدة ← الاستكشافي، ثم المكتوب حين يُعرف.
- حقل أعيدت تسميته أو تغيّر نوعه في إصدار ← اختبار العقد.
- مستهلك يسيء التعامل مع 429 أو مهلة ← المحاكاة.
- استعلام يعمل جيداً لمستخدم واحد ويفشل عند مئة ← اختبار الحمل.
- انحدار في شيء كان يعمل الشهر الماضي ← اختبارات مكتوبة في CI.
| الأسلوب | يلتقطمع مثال على الفشل | يفوته |
|---|---|---|
| الاختبار الاستكشافي | منطق العمل الخاطئ ورسائل الخطأ المربكة والسلوك غير الموثقمنطق عمل خاطئ في نقطة نهاية جديدة (ثم يُكتب اختباره حين يُعرف) | الانحدار، لأن شيئاً لا يعيد تشغيله |
| الاختبارات المكتوبة | الانحدار في المسارات التي كُتبت لهاانحدار في شيء كان يعمل الشهر الماضي، يُلتقط في CI | كل شيء آخر |
| اختبار العقد | التغييرات الكاسرة في شكل الواجهةحقل أعيدت تسميته أو تغيّر نوعه في إصدار | القيم الخاطئة داخل شكل صحيح |
| المحاكاة | عيوب المستهلك، باختبار المستهلكين بمعزل وفرض مسارات الخطأمستهلك يسيء التعامل مع 429 أو مهلة | السلوك الفعلي للواجهة الحقيقية، ولهذا يجب أن يربط عقدٌ المحاكاةَ بالحقيقة |
| اختبار الحمل | مشكلات السعة والتزامناستعلام يعمل جيداً لمستخدم واحد ويفشل عند مئة | المشكلات الوظيفية كلياً |
اختبار العقد: المواصفة مرجعاً
عقد الواجهة البرمجية وصف قابل للقراءة آلياً لكل عملية: المسارات والطرق والمعاملات ومخططات الطلب والاستجابة ورموز الحالة والمصادقة. OpenAPI هي الصيغة الشائعة لواجهات HTTP؛ وتحمل GraphQL مخططها الخاص؛ ولـ SOAP ملف WSDL. ومع وجود العقد لا يحتاج الاختبار إلى تأكيدات مكتوبة يدوياً لكل حقل — يفحص المدقق أن الاستجابة تطابق المخطط لرمز الحالة ذاك، وأي انحراف فشل.
يعمل اختبار العقد في اتجاهين. من جهة المزوّد، تُفحص استجابات الواجهة مقابل مواصفتها، فيُلتقط انحراف التنفيذ عن المستند. ومن جهة المستهلك (العقود المدفوعة بالمستهلك)، يسجل كل مستهلك الجزء الذي يعتمد عليه من الواجهة، ويُختبر المزوّد مقابل توقعات كل مستهلك قبل شحن أي تغيير. الأول رخيص ويلتقط معظم الكسور؛ والثاني هو ما تنمو إليه منصة ذات عملاء كثيرين.
- تحقق من المواصفة نفسها أولاً — فمستند OpenAPI غير الصالح ينتج نتائج اختبار بلا معنى.
- اختبر استجابات الخطأ مقابل العقد أيضاً؛ فأجسام 4xx و5xx تنحرف أكثر من أجسام 200.
- ولّد حالات الاختبار الأولى من المواصفة، ثم أضف حالات قواعد العمل التي لا يستطيع المولّد معرفتها.
جرّبها: مدقّق OpenAPI جرّبها: مدقّق عقود API جرّبها: مقارنة عقود الاستجابات جرّبها: مولّد حالات اختبار من OpenAPI
المحاكاة: اختبار المستهلك ومسارات الخطأ
المحاكاة بديل عن واجهة حقيقية يعيد الاستجابات التي تختارها. وهي الطريقة التي تُختبر بها واجهة أمامية أو خدمة تابعة قبل بناء الواجهة الحقيقية، والطريقة التي تُستبدل بها خدمة خارجية لا يمكن استدعاؤها في الاختبار (بوابة دفع أو سجل حكومي)، و— وهذا الأثمن — الطريقة التي تُنتج بها مسارات الخطأ متى شئت: 503 مع ترويسة Retry-After، أو 429، أو استجابة تصل بعد 30 ثانية، أو جسم JSON صالح لكن بالشكل الخاطئ.
وخطر المحاكاة أنها توافق المستهلك لا الواقع. وعادتان تحتويانه: ولّد المحاكاة من العقد نفسه الذي يُختبر المزوّد مقابله، وشغّل اختباراً واحداً على الأقل مقابل الواجهة الحقيقية في بيئة تجريبية قبل الإصدار.
جرّبها: مولّد استجابات API وهمية جرّبها: مولّد حمولات خطأ وهمية جرّبها: محاكي رموز حالة API
REST وGraphQL وSOAP وWebhooks: ما الذي يتغير
- REST عبر HTTP — رموز الحالة تحمل معنى (RFC 9110) فيتحقق الاختبار منها؛ وللموارد عناوين URL فيمكن اختبار التخزين المؤقت والتكافؤ لكل طريقة؛ وينبغي أن تتبع الأخطاء شكلاً موثقاً، ويُفضَّل صيغة Problem Details في RFC 9457.
- GraphQL — نقطة نهاية واحدة، ورمز حالة واحد عادة (200) حتى للأخطاء، التي تعيش في مصفوفة errors في الجسم. يجب أن تتحقق الاختبارات من الجسم لا من الحالة؛ والمخطط متاح دائماً لاختبار العقد؛ وعمق الاستعلام وتعقيده يحتاجان إلى اختبارات حمل لأن طلباً واحداً قد يكون مكلفاً بلا حدود.
- SOAP — مغلفات XML يصفها ملف WSDL؛ والتحقق مقابل XSD هو اختبار العقد؛ والأعطال مهيكلة؛ والأدوات أقدم لكن انضباط العقد هو الأشد بين الأربعة.
- Webhooks — الواجهة تستدعيك، فيحتاج الاختبار إلى مستقبِل يسجل ما وصل، ويفحص التوقيع (عادة HMAC على الجسم بسر مشترك)، ويتحقق من إعادة المحاولات والترتيب. ويجب اختبار المستهلك أيضاً للتسليمات المكررة، لأن «مرة واحدة على الأقل» هي القاعدة.
جرّبها: مختبِر استعلامات GraphQL جرّبها: مختبِر طلبات SOAP جرّبها: مختبِر Webhook جرّبها: محلّل توقيعات Webhook
اختيار المزيج
لمعظم المنتجات المزيج هو: حزمة مكتوبة متحقق منها بالعقد على مستوى الواجهة تعمل في CI (العمود الفقري)، وجلسات استكشافية على كل نقطة نهاية جديدة أو متغيرة، ومحاكاة لكل اعتمادية خارجية ولمسارات الخطأ، واختبار حمل بأرقام حقيقية قبل الإطلاق وبعد أي تغيير في مسار ساخن. أما الطلبات الاستكشافية وحدها — الطريقة التي يبدأ بها معظم اختبار الواجهات عملياً — فينبغي أن تكون جزءاً من ذلك المزيج لا كله.
اخرج عن الافتراضي حين تكون الواجهة منتجاً عاماً (أضف العقود المدفوعة بالمستهلك واختبارات الإصدارات)، أو حين تواجه عملية منظّمة (أضف اختبارات الأمان من قائمة OWASP API Security Top 10، وخاصة التفويض على مستوى الكائن)، أو حين تكون داخلية وتتغير يومياً (اعتمد أكثر على اختبارات العقد وأقل على التأكيدات المكتوبة يدوياً، لأنها تنجو من التغيير).
جرّبها: مولّد اختبارات الطلبات المتزامنة جرّبها: مختبِر مصادقة API
الأسئلة الشائعة
هل يكفي Postman لاختبار الواجهات البرمجية؟
Postman والعملاء المشابهون ممتازون للطلبات الاستكشافية ويمكنهم تشغيل مجموعات محفوظة بتأكيدات في CI، وهذا يغطي الأسلوبين الأولين. لكنهم لا يقدمون بأنفسهم التحقق من العقد مقابل مواصفة، أو محاكاة مسارات الخطأ على نطاق واسع، أو اختبار الحمل بتزامن واقعي؛ فتلك تحتاج إلى المواصفة وطبقة محاكاة وأداة حمل إلى جانبهم.
ما الفرق بين اختبار العقد واختبار التكامل؟
يستدعي اختبار التكامل الواجهة الحقيقية ويفحص السلوك الحقيقي من طرف إلى طرف، بما فيه البيانات والآثار الجانبية. أما اختبار العقد فيفحص فقط أن الطلبات والاستجابات تطابق الشكل المتفق عليه، ويمكن أن يعمل دون الاعتمادية الحقيقية. اختبارات العقد أسرع وأكثر استقراراً؛ واختبارات التكامل تلتقط ما لا تستطيعه العقود — القيم الخاطئة والبيانات الخاطئة والآثار الجانبية الخاطئة. وتحتاج معظم الحزم إلى كليهما، مع الكثير من الأول.
هل ما زلنا نحتاج إلى المحاكاة إذا كانت لدينا بيئة تجريبية؟
نعم، لسببين. لا تستطيع البيئة التجريبية إنتاج مسارات الخطأ عند الطلب — لا يمكنك أن تطلب من بوابة دفع حقيقية أن تنتهي مهلتها في اللحظة التي يحتاجها اختبارك — واعتماديات البيئة التجريبية مشتركة وبطيئة، وهذا يجعل الاختبارات متقلبة. تمنح المحاكاة اختبارات حتمية وسريعة؛ وتمنح البيئة التجريبية تأكيداً نهائياً واحداً مقابل الواقع.
كيف ينبغي اختبار أخطاء الواجهة البرمجية؟
ينبغي أن يكون لكل استجابة خطأ موثقة اختبار: رمز الحالة، وشكل الجسم (ويُفضَّل Problem Details في RFC 9457)، وأن لا تتسرب أي تفاصيل حساسة — لا تتبّع مكدس ولا SQL ولا أسماء مضيفين داخلية. ثم غير الموثقة: JSON مشوّه، ونوع محتوى خاطئ، وأجسام ضخمة، ومصادقة مفقودة، ورموز منتهية. فمسارات الخطأ هي حيث تعيش معظم الاكتشافات الأمنية.
بأي أسلوب ينبغي أن يبدأ الفريق؟
بالعقد. كتابة مستند OpenAPI أو التحقق منه أولاً يمنح كل أسلوب آخر شيئاً يُختبر مقابله، ويولّد أولى الحالات المكتوبة والمحاكاة، ويفرض الإجابة عن أسئلة التصميم — رموز الحالة وأشكال الأخطاء والترقيم — قبل أن تُنفَّذ بثلاث طرق مختلفة.
المراجع
- RFC 9110: HTTP Semanticsمعاني أساليب HTTP وحقول الترويسات ورموز الحالة والتفاوض على المحتوى، بغضّ النظر عن إصدار البروتوكول.
- OpenAPI Specificationالمعيار لوصف واجهات REST: المسارات والعمليات والمعاملات والمخططات والاستجابات وأنظمة الأمان.
- GraphQL Specificationلغة استعلام GraphQL ونظام أنواعها وقواعد التحقق ودلالات التنفيذ.
- RFC 9457: Problem Details for HTTP APIsصيغة الخطأ application/problem+json (type وtitle وstatus وdetail وinstance) لأخطاء API القابلة للقراءة آلياً.
- Postman Docsالتوثيق الرسمي لعميل API المستخدم لإرسال الطلبات وكتابة سكربتات الاختبار وتشغيل المجموعات.
- OWASP API Security Top 10 (2023)أكثر عشر نقاط ضعف شيوعاً في واجهات API: خلل التفويض على مستوى الكائن، وخلل التوثيق، والاستهلاك غير المقيد للموارد، وغيرها.
- Apache JMeter User's Manualكيف تُبنى اختبارات الحمل وتُعامَل بالمعاملات وتُشغَّل في JMeter، وكيف تُقرأ مستمعاته وتقاريره.
تمرين عملي
اختر مزيج اختبار الواجهة البرمجية لمنصة توصيل
أنت المختبِر الوحيد في فريق الواجهة البرمجية لمنصة خيالية لتوصيل البقالة. تستدعي واجهتَها REST ثلاثُ جهات: تطبيقات Android وiOS، ولوحة المتاجر الشريكة عبر نقطة نهاية GraphQL، وبوابة دفع خارجية ترسل Webhooks. أفلتت ثماني مشكلات من الاختبار في الربع الماضي، وتبدأ حملة ترويجية وطنية بعد ما يزيد قليلاً على خمسة أسابيع. تصف المادة أدناه من يستدعي الواجهة، وكيف تُختبر اليوم، والمشكلات الثماني من I1 إلى I8، وسؤالاً من قائد الفريق.
اعمل بالأساليب الخمسة في الدليل — الطلبات الاستكشافية، والاختبارات الوظيفية المكتوبة، واختبار العقد، والمحاكاة، واختبار الحمل — وبما يقوله عن REST وGraphQL وWebhooks. تكفي الورقة والقلم؛ وخصّص لذلك 30–45 دقيقة. وإن أردت أن ترى مغزى I7 بنفسك، فوقّع جسماً تجريبياً قصيراً بأي سر في أداة «مولّد HMAC»، ثم غيّر حرفاً واحداً في الجسم، وافحص النسختين بأداة «محلّل توقيعات Webhook» من الدليل.
منصة لتوصيل البقالة (مثال خيالي) - REST API v2، ستة مطوّرين ومختبِر واحد
اليوم: الاثنين 5 أكتوبر 2026. تبدأ حملة ترويجية وطنية يوم الخميس 12 نوفمبر 2026.
من يستدعي الواجهة
تطبيقا Android وiOS العملاء يحدّثون تطبيقاتهم ببطء؛ وإصدارات التطبيق من
الأشهر الستة الأخيرة ما زالت مستخدمة
لوحة المتاجر الشريكة شاشة الطلبيات لدى المتاجر؛ تستخدم نقطة نهاية GraphQL
POST /graphql
بوابة الدفع (خارجية) تستدعيها واجهتنا لتحصيل الدفعة، وتعاود هي الاتصال بنا على
POST /webhooks/payments بحدث payment.succeeded أو
payment.failed؛ لكل حدث معرّف فريد وترويسة X-Signature
(توقيع HMAC-SHA256 للجسم بسر مشترك). وتقول وثائقها إن
الأحداث تُسلَّم مرة واحدة على الأقل.
كيف تُختبر الواجهة اليوم
قبل كل إصدار (كل أسبوعين) يرسل المختبِر طلبات مجموعة Postman يدوياً ويقرأ
الاستجابات. لا يعمل أي اختبار للواجهة في CI.
يوجد مستند OpenAPI، وكان آخر تحديث له قبل خمسة أشهر.
بيئة Sandbox الخاصة بالبوابة توافق على كل دفعة اختبارية فوراً.
ما الذي حدث في الربع الماضي (كُشفت I7 في مراجعة كود، والباقي في الإنتاج)
I1 غيّر الإصدار 2.14 اسم حقل في GET /api/v2/cart، وعدّل واجهة الويب في الإصدار
نفسه. فصار تطبيق Android 5.2 يعرض كل رسوم توصيل على أنها 0.00.
2.13 {"subtotal": 84.50, "deliveryFee": 9.00, "total": 93.50}
2.14 {"subtotal": 84.50, "delivery_fee": 9.00, "total": 93.50}
I2 أجابت البوابة بعد 40 ثانية. وتوقفت واجهتنا عن الانتظار بعد 30 ثانية وأعادت 500،
فعرض التطبيق «فشل الدفع». دفع العملاء مرة أخرى، لكن الدفعة الأولى كانت قد تمت:
فخُصم المبلغ منهم مرتين.
I3 جديد في 2.15: POST /api/v2/cart/promo. رمز الخصم WELCOME50 صالح مرة واحدة لكل
عميل، لكنه قُبل مرة أخرى في الطلبية الثانية لأحد العملاء.
I4 في ذروة المساء أثناء الحملة الماضية، استغرق GET /api/v2/orders (سجل الطلبيات)
أكثر من 20 ثانية، ثم أعاد 504 لمدة 25 دقيقة. لكل عميل اختباري نحو 30 طلبية؛
وللعملاء القدامى في الإنتاج ما يصل إلى 2000 طلبية.
I5 بعد تغيير، عرضت اللوحة قائمة طلبيات فارغة لكل متجر لديه أكثر من 100 طلبية
مفتوحة، لمدة يومين. وفحص الصحة (Health check) في اللوحة لا ينظر إلا إلى رمز
الحالة:
HTTP/1.1 200 OK
{"data": {"storeOrders": null},
"errors": [{"message": "Result too large", "path": ["storeOrders"]}]}
I6 سلّمت البوابة حدث payment.succeeded نفسه مرتين (إعادة محاولة). فوُسمت الطلبية
مدفوعة مرتين وصدرت فاتورتان.
I7 تقبل POST /webhooks/payments أيضاً طلباً بلا ترويسة X-Signature: فأي شخص يعرف
العنوان يستطيع أن يَسِم أي طلبية بأنها مدفوعة.
I8 عمل المرشّح inStock=true في GET /api/v2/stores/{id}/products في الإصدار 2.12
وتعطّل في 2.13: ظهرت منتجات نفدت كميتها. ولم تشمل الجولة اليدوية في ذلك
الإصدار المرشّحات.
سؤال قائد الفريق
«قبل الحملة، هل يمكننا أن نستمر في الاختبار اليدوي في Postman ونكتفي بإضافة
مختبِر ثانٍ؟»- لكل مشكلة من I1 إلى I8، سمِّ الأسلوب الذي كان الأرجح أن يكشفها قبل الإصدار، واذكر في جملة واحدة لماذا فاتت الجولةَ اليدوية في Postman.
- لمشكلة GraphQL ومشكلتي Webhooks، اكتب ما يجب أن يتحقق منه الاختبار أو أن يُنتجه، مما لا يغطيه فحص رمز الحالة المعتاد في REST.
- لكل أسلوب اخترته، سمِّ شيئاً واحداً سيظل يفوته في هذا المنتج، وأي جزء آخر من المزيج يسدّ هذه الثغرة.
- اقترح مزيج الفريق: ما يعمل مع كل بناء، ولكل نقطة نهاية جديدة أو متغيرة، وقبل كل إصدار، وقبل الحملة؛ وأين يخرج هذا المنتج عن المزيج الافتراضي في الدليل؛ وما الذي تبدأ به أولاً، من اليوم.
- أجب عن سؤال قائد الفريق في ثلاث جمل أو أربع.
إظهار الإجابة النموذجية
النمط أولاً. تحصل الواجهة اليوم على أسلوب واحد هو الطلبات الاستكشافية، بل ليس حتى استكشافاً حقيقياً: المجموعة نفسها تُعاد يدوياً قبل كل إصدار. وفي أحسن الأحوال كان يمكن لذلك أن يكشف I3 وI7، وكذلك I5 لو وُجد متجر اختباري كبير بما يكفي. أما كل مشكلة أخرى فكانت تحتاج إلى أسلوب لا يستخدمه الفريق. تسمّي الإجابة النموذجية أدناه لكل مشكلة الأسلوبَ الأرجح أن يكشفها قبل الإصدار، ولماذا فاتت الجولةَ اليدوية؛ ثم ما يظل كل أسلوب يفوته، والمزيج، والرد على قائد الفريق.
I1: اختبار العقد من جهة المزوّد. إذا فُحصت كل استجابة لـ GET /api/v2/cart في CI مقابل مستند OpenAPI، يفشل البناء لحظة اختفاء deliveryFee، بشرط أن يجعل المخطط deliveryFee حقلاً إلزامياً (required)؛ فتحقّق من ذلك، لأن المخطط الذي كل حقوله اختيارية يقبل الاستجابة بعد إعادة التسمية. وفاتت المشكلةُ الجولةَ اليدوية لأن "delivery_fee": 9.00 يبدو معقولاً تماماً لأي شخص، وواجهة الويب التي عُدّلت في الإصدار نفسه لم تُظهر أي مشكلة. والتطبيقات المثبّتة هي سبب حاجة هذا الفريق أيضاً إلى العقود المدفوعة بالمستهلك: يسجّل كل إصدار من التطبيق ما زال مستخدماً الحقولَ التي يقرؤها، فيفشل أي تغيير لدى المزوّد يكسر أحدها قبل شحنه. والحقل الذي يجب أن يُعاد تسميته يُرسَل عندئذ بالاسمين معاً، أو في إصدار جديد من الواجهة، حتى يتوقف استخدام التطبيقات القديمة.
I2: المحاكاة. بيئة Sandbox الخاصة بالبوابة توافق على كل دفعة فوراً، فلا الطلب اليدوي ولا التشغيل في البيئة التجريبية (Staging) يستطيع أن يُنتج بوابة تجيب بعد 40 ثانية. أما محاكاة البوابة فتستطيع ذلك، ومعه مسارات الخطأ الأخرى: لا إجابة على الإطلاق، و503 مع ترويسة Retry-After، و429، وجسم JSON صالح لكن بالشكل الخاطئ. ويجب الاتفاق مع الفريق على ما تفعله الواجهة حين تكون نتيجة الدفع مجهولة، مثل أن تعرض الدفعة «قيد المعالجة» وتسأل البوابة عن حالتها بدلاً من الإبلاغ عن فشل؛ ويتحقق الاختبار مما يهم العميل: طلبية واحدة، ومبلغ يُخصم منه مرة واحدة فقط. ثم يعمل الاختبار مقابل المحاكاة في CI مع كل بناء. وقبل كل إصدار، يؤكد تشغيل واحد من البيئة التجريبية مقابل بيئة Sandbox الحقيقية أن المحاكاة ما زالت تتصرف مثل البوابة.
I3: الاختبار الاستكشافي، ثم اختبار مكتوب. يجتاز اختبار العقد الخصمَ الثاني، لأن الاستجابة بالشكل الصحيح تماماً: هذا منطق عمل خاطئ في نقطة نهاية جديدة. والمختبِر الذي يستكشف POST /api/v2/cart/promo بميثاق اختبار (Charter) مثل «اكسر قاعدة المرة الواحدة لكل عميل» يجرّب الرمز في طلبية ثانية، وبعد إلغاء الطلبية الأولى، ومن جهازين في اللحظة نفسها، وبأحرف صغيرة (welcome50). أما الجولة اليدوية فتعيد مجموعة ثابتة، والقاعدة الجديدة هي بالضبط ما لا تحويه: إرسال الطلبات يدوياً ليس هو الاستكشاف. وكل حالة تُكتشف تصبح اختباراً مكتوباً حتى تبقى القاعدة مُصلَحة.
I4: اختبار الحمل بمجموعة بيانات واقعية. لا تستطيع الطلبات اليدوية إظهار المشكلة: شخص واحد يرسل طلباً واحداً في كل مرة، لعملاء اختباريين لكل منهم نحو 30 طلبية، بينما يحتاج الإخفاق إلى عملاء كثيرين لكل منهم ما يصل إلى 2000 طلبية في اللحظة نفسها. أنشئ بيانات اختبار بأعداد طلبيات تشبه الإنتاج، واتفق مع مالك المنتج على الأهداف قبل الاختبار (زمن استجابة ومعدل خطأ عند الذروة المتوقعة)، وشغّله مبكراً بما يكفي لإصلاح ما يكشفه وإعادة تشغيله قبل 12 نوفمبر، ثم مجدداً بعد أي تغيير في سجل الطلبيات، فهو مسار ساخن. ولا يقول اختبار الحمل شيئاً عن صحة الطلبيات المعروضة.
I5: اختبارات مكتوبة تتحقق من جسم استجابة GraphQL. يجيب خادم GraphQL عادة بـ200 حتى حين يفشل حقل، ويضع الإخفاق في مصفوفة errors، فيبقى فحص رمز الحالة أخضر، سواء كان فحص الصحة في اللوحة أم اختباراً. يتحقق الاختبار من غياب errors ومن أن data.storeOrders قائمة فيها الطلبيات المتوقعة، ويعمل بمتاجر اختبارية على جانبي النقطة التي تعطّل عندها: 100 و101 طلبية مفتوحة (تحليل القيم الحدّية ثنائي القيم). ولن يكشفها فحص العقد مقابل مخطط GraphQL وحده: فقد عادت storeOrders بقيمة null بجوار الخطأ، وهذا لا يفعله GraphQL إلا لحقل يعلنه المخطط قابلاً لقيمة null. أصلح فحص الصحة بالطريقة نفسها، وأضف متجراً بأكبر حجم واقعي إلى اختبار الحمل، لأن طلب GraphQL واحداً قد يكون مكلفاً جداً.
I6: اختبار Webhook يؤدي فيه الاختبار دور البوابة. عبارة «تُسلَّم مرة واحدة على الأقل» تعني أن التكرار أمر طبيعي لا عطل في البوابة، فيجب أن يتعامل المستقبِل معه. يرسل الاختبار حدث payment.succeeded الموقّع نفسه، بمعرّف الحدث نفسه، مرتين، ويتحقق من طلبية مدفوعة واحدة وفاتورة واحدة؛ ويرسل اختبار ثانٍ الأحداث بترتيب مختلف، مثل payment.failed بعد payment.succeeded للدفعة نفسها، ويتحقق من النتيجة التي حددها الفريق (واسأل عنها إن لم تكن مكتوبة). ولا يمكن أن تُطلب من بيئة Sandbox إعادة المحاولة في اللحظة التي يحتاجها الاختبار، لذا فهذه محاكاة، أي إنتاج سلوك البوابة عند الطلب، تعمل اختباراً مكتوباً في CI.
I7: اختبارات سلبية مكتوبة لمستقبِل Webhook، وعيب أمني. يجب أن تُرفض ثلاثة طلبات برمز الخطأ الذي يوثّقه الفريق (مثل 401) وأن تبقى الطلبية دون تغيير: طلب بلا ترويسة X-Signature، وتوقيع بسر خاطئ، وجسم موقّع توقيعاً صحيحاً ثم عُدّل بعد التوقيع. والأخير هو ما يُظهره تمرين «مولّد HMAC»: تغيير حرف واحد يعطي توقيعاً مختلفاً. لم تحوِ المجموعة إلا استدعاءات صالحة من البوابة، فلم ترسل الجولة اليدوية طلباً كهذا قط؛ ومراجعة الكود التي كشفته اختبار ساكن، والاختبار المكتوب هو ما يبقيه مُصلَحاً. ولأن الواجهة تنقل أموالاً وتحفظ بيانات شخصية للعملاء، أضف إلى المزيج اختبارات من OWASP API Security Top 10 2023، بدءاً بالتفويض على مستوى الكائن: يجب ألا يستطيع عميل أن يقرأ سلة عميل آخر أو طلبياته أو يغيّرها. ولا تختبر إلا أنظمة مأذوناً لك باختبارها، وهي هنا البيئة التجريبية لفريقك.
I8: اختبارات وظيفية مكتوبة في CI. هذا انحدار: مرشّح عمل في الإصدار 2.12 وتعطّل في 2.13، في إصدار لم تشمل جولته اليدوية المرشّحات مصادفةً. واختبار يتحقق من أن inStock=true لا يعيد أي منتج كميته صفر، ضمن حزمة تعمل مع كل بناء، كان سيفشل عند التغيير الذي كسره. ويجتازه اختبار العقد، لأن المنتج النافد في القائمة بالشكل الصحيح.
ما يظل كل أسلوب يفوته في هذا المنتج، وما يسدّ الثغرة. يفوت اختبارَ العقد القيمُ الخاطئة داخل شكل صحيح، مثل I3 وI8 وقيمة null في I5، فتتحقق الاختبارات المكتوبة من قواعد العمل. ولا تجد الاختبارات المكتوبة إلا ما كُتبت لتجده، والقاعدة الجديدة مثل I3 ليست بينها، فتحصل كل نقطة نهاية جديدة أو متغيرة على جلسة استكشافية. والجلسة الاستكشافية لا تثبت شيئاً بعد انتهائها، فيصبح كل اكتشاف اختباراً مكتوباً. ومحاكاة البوابة توافق فريقك وليس بالضرورة البوابة، فتُبنى من وثائق واجهة البوابة نفسها وتُفحص من البيئة التجريبية مقابل بيئة Sandbox الحقيقية قبل كل إصدار. واختبار الحمل لا يقول شيئاً عن الصحة الوظيفية، فقد يكون سجل الطلبيات سريعاً وخاطئاً معاً، وهذا ما تغطيه حزمة CI.
المزيج. مع كل بناء في CI: حزمة اختبارات الواجهة المكتوبة، وبين أول اختبارات الانحدار فيها I1 إلى I8؛ وفحص كل استجابة مقابل مستند OpenAPI، بما فيها استجابات الخطأ؛ واختبارات GraphQL تتحقق من الجسم؛ واختبارات Webhook في I6 وI7؛ ومحاكاة البوابة لمسارات الخطأ. ولكل نقطة نهاية جديدة أو متغيرة: جلسة استكشافية قصيرة تصبح اكتشافاتها اختبارات مكتوبة. وقبل كل إصدار: تشغيل واحد من البيئة التجريبية مقابل بيئة Sandbox الحقيقية للبوابة. وقبل الحملة، وبعد أي تغيير في مسار ساخن مثل سجل الطلبيات: اختبار حمل ببيانات تشبه الإنتاج. هذا هو المزيج الافتراضي في الدليل مع خروجين عنه. فالتطبيقات المثبّتة لا يمكن تحديثها مع الواجهة في الوقت نفسه، إذ ما زالت إصدارات الأشهر الستة الأخيرة مستخدمة، لذا تتصرف الواجهة بالنسبة إليها كمنتج عام وتحتاج إلى العقود المدفوعة بالمستهلك واختبارات لكل إصدار من التطبيق ما زال مدعوماً. وهي تنقل أموالاً وبيانات شخصية، فتحتاج إلى اختبارات OWASP API Security Top 10.
ما تبدأ به أولاً، اليوم: العقد. حدّث مستند OpenAPI الذي مضت على آخر تحديث له خمسة أشهر ليطابق الواجهة، وتحقق من صلاحيته، لأن المستند القديم أو غير الصالح يجعل كل نتيجة لاختبار العقد بلا معنى؛ ثم ولّد منه أولى الحالات المكتوبة (تساعدك أداة «مولّد حالات اختبار من OpenAPI» في الدليل)، وأضف حالات قواعد العمل التي لا يستطيع المولّد معرفتها، مثل I3. ومع نحو خمسة أسابيع حتى 12 نوفمبر، يكون الترتيب العملي: العقد وفحوص العقد في CI؛ ثم الحزمة المكتوبة مع I1 إلى I8 ومحاكاة البوابة واختبارات Webhook؛ ثم اختبار الحمل، مبكراً بما يكفي لإصلاح ما يكشفه وإعادة تشغيله قبل الحملة.
الرد على قائد الفريق: «لا، فإضافة أشخاص يرسلون الطلبات يدوياً تجيب عن سؤال واحد فقط من الأسئلة الخمسة. فمن مشكلات الربع الماضي الثماني، كان يمكن للطلبات اليدوية في أحسن الأحوال أن تكشف I3 وI7 وربما I5؛ ولم يكن بوسعها إظهار I1، لأن الحقل المعاد تسميته يبدو سليماً لأي شخص، ولا I2 وI6، لأن بيئة Sandbox لا تستطيع إنتاج إجابة بطيئة أو إعادة محاولة، ولا I4، لأن شخصاً واحداً لا يستطيع إنتاج ذروة الحملة؛ ثم لا يبقى شيء مما تكشفه مفحوصاً بعد ذلك، وهكذا وقعت I8. يستطيع Postman تشغيل مجموعات محفوظة بتأكيدات في CI، وهذا يغطي الاختبارات المكتوبة، لكن التحقق من العقد ومحاكاة البوابة واختبار الحمل تحتاج إلى المواصفة وطبقة محاكاة وأداة حمل إلى جانبه. والأفضل أن يُخصَّص المختبِر الثاني لجلسات استكشافية على نقاط النهاية الجديدة ولتحويل اكتشافاتها إلى اختبارات مكتوبة».
راجع عملك. يجب أن يكون لكل مشكلة أسلوب، وسبب فاتت به الممارسةَ الحالية. والتوزيعات الأخرى مقبولة إن ذُكر السبب، مثل وضع I7 تحت الاختبار الاستكشافي بشرط أن تضيف أن الاختبار المكتوب وحده يبقيه مُصلَحاً، أو I6 تحت الاختبارات المكتوبة بشرط أن تذكر أن التسليم المكرر يجب أن يُنتَج عند الطلب. ويجب أن يذكر مزيجك متى يعمل كل أسلوب (مع كل بناء، ولكل نقطة نهاية جديدة، وقبل كل إصدار، وقبل الحملة) وما يفوت كلاً منها. وبمصطلحات ISTQB CTFL v4.0: مستند OpenAPI هو أساس الاختبار (Test basis)، وهو المرجع (Test oracle) لاختبارات العقد؛ والاختبار الاستكشافي تقنية اختبار قائمة على الخبرة (Experience-based)؛ وحزمة CI هي اختبار الانحدار (Regression testing)، وإصلاح كل مشكلة من I1 إلى I8 يحتاج أولاً إلى اختبار التأكيد (Confirmation testing)؛ واختبار الحمل اختبار غير وظيفي لكفاءة الأداء (Performance efficiency) وفق ISO/IEC 25010؛ والتشغيل مقابل البوابة الحقيقية من البيئة التجريبية اختبار تكامل النظام (System integration testing).
تقدّمك في هذا الموضوع
سجّل الدخول لتتابع تقدّمك
علّم الموضوعات مكتملة، وتابع من حيث توقفت، وافتح امتحانات التخصص.
جزء من مسار تعلم ضمان الجودة
قبل هذا الموضوع
الموضوعات التالية
الأدوات المذكورة في هذا الدليل
أنشئ طلبات HTTP وأرسلها (الطريقة وعنوان URL والترويسات والمصادقة والجسم) وافحص الاستجابة — بديل خفيف لـ Postman داخل متصفحك.
اختبر نقاط نهاية REST بتحكم كامل في الطريقة والترويسات وجسم JSON، ثم أضف تأكيدات على الحالة والترويسات ومسارات JSON.
تحقّق من استجابة API وفق التوقعات: الحالة والترويسات المطلوبة وJSON Schema وقواعد الحقول.
التحقق من مستندات OpenAPI 3.x وSwagger 2.0 للكشف عن الأخطاء البنيوية ومشكلات أفضل الممارسات.
التحقق من مطابقة زوج طلب/استجابة API لعقد OpenAPI الخاص به: المسار والطريقة والمعاملات والجسم ومخطط الاستجابة.
مقارنة استجابة API فعلية بعقد متوقَّع (مثال أو مخطط) والإبلاغ عن الفروق الكاسرة وغير الكاسرة.
ولّد مصفوفة حالات اختبار منظّمة (إيجابية وسلبية ومصادقة وقيم حدّية) من مواصفة OpenAPI / Swagger.
ولّد استجابات API وهمية كاملة (الحالة والترويسات وجسم JSON) لحالات النجاح والقوائم والتفاصيل والأخطاء والنتائج الفارغة.
ولّد حمولات أخطاء تحقق على مستوى الحقل للنماذج وواجهات API، بالجملة، لاختبار حالات الخطأ في واجهة المستخدم.
شغّل استعلامات GraphQL وتعديلاتها (mutations) مع المتغيرات والترويسات على أي نقطة نهاية وافحص الاستجابة.
أرسل مغلّفات SOAP 1.1 / 1.2 مع ترويسات SOAPAction واعرض استجابة XML منسّقة.
احصل على عنوان URL فريد، وأرسل إليه طلبات webhook، وافحص الطريقة والترويسات والجسم والتوقيت في الوقت الفعلي.
تحقّق من توقيعات webhook (بأنظمة HMAC-SHA256/SHA1 وStripe وGitHub وShopify وSlack) باستخدام سرّك — محلياً.
ولّد سكربتات اختبار التزامن (k6 وJMeter JMX وLocust وArtillery وNode.js) بإعدادات افتراضية آمنة لنقطة نهاية مستهدفة.
احصل على نقطة نهاية عامة تعيد أي رمز حالة HTTP، مع تأخير اختياري وجسم JSON مخصّص، لاختبار معالجة الأخطاء في العميل.