إن كتابة نص برمجي للاختبار الآلي أمر سهل. الجزء الصعب هو كتابة نص يبقى مفيدًا بعد ستة أشهر: لا يعتمد على حالة مخفية، ولا يفشل بسبب تغييرات غير مرتبطة، ولا يكتفي بفحص سطحي مثل 200 OK. نص الاختبار الجيد يكون دقيقًا، معزولًا، قابلًا للتكرار، ويشرح سبب الفشل بوضوح.
يغطي هذا الدليل ماهية النص البرمجي للاختبار الآلي، والبنية العملية التي تجعله موثوقًا، وطريقتين لكتابة نصوص اختبار API، ثم خطوات بناء سيناريو اختبار في Apidog.
ما هو النص البرمجي للاختبار الآلي
النص البرمجي للاختبار الآلي هو مجموعة تعليمات قابلة للتكرار تختبر جزءًا من برنامجك دون تدخل يدوي. يرسل الاختبار إدخالًا، ينفذ إجراءً، ثم يقارن النتيجة الفعلية بالنتيجة المتوقعة.
بشكل مبسط:
Input -> Action -> Assertion -> Pass/Fail
النص البرمجي للاختبار هو النسخة التنفيذية من حالة الاختبار. حالة الاختبار تصف القصد بلغة بشرية: الإدخال، الإجراء، والنتيجة المتوقعة. أما النص البرمجي فيحوّل ذلك إلى خطوات يمكن تشغيلها في كل commit أو ضمن خط CI/CD.
عادةً:
- حالة اختبار واحدة ⟶ نص اختبار واحد.
- سيناريو اختبار ⟶ عدة نصوص أو خطوات مترابطة.
القيمة الحقيقية للاختبار الآلي هي أنه يعمل بالطريقة نفسها في كل مرة. لذلك يجب أن يكون الاختبار حتميًا. إذا كان يعتمد على ترتيب تشغيل اختبارات أخرى، أو على بيانات تركها تشغيل سابق، فهو ليس أتمتة موثوقة بل مصدر لفشل عشوائي.
بنية نص الاختبار الموثوق به
معظم نصوص الاختبار الجيدة، بغض النظر عن اللغة أو الأداة، تتبع نمطًا واحدًا:
Arrange -> Act -> Assert -> Cleanup
1. الترتيب Arrange
جهّز كل ما يحتاجه الاختبار:
- بيانات الإدخال.
- المصادقة.
- الشروط المسبقة.
- بيانات الاختبار المطلوبة.
لا تفترض أن البيانات موجودة مسبقًا في قاعدة البيانات. إذا كان الاختبار يحتاج إلى مستخدم، فإما أن ينشئه الاختبار، أو يستخدم fixture معروفًا ومسيطرًا عليه.
مثال عملي:
Arrange:
- إنشاء مستخدم اختبار
- الحصول على token
- تجهيز body الطلب
2. التنفيذ Act
نفّذ الإجراء الوحيد الذي تريد اختباره.
مثال:
Act:
POST /orders
اختبر سلوكًا واحدًا في كل نص. إذا كان النص ينشئ طلبًا، ويعدّله، ويحذفه، ويتحقق من الفاتورة في نفس الوقت، فسيصبح تشخيص الفشل أصعب.
3. التحقق Assert
هنا يثبت الاختبار قيمته. لا تكتفِ بأن الطلب لم يفشل أو أن الحالة 200.
تحققات API الجيدة تشمل:
- كود الحالة الصحيح.
- وجود الحقول المطلوبة.
- صحة القيم المهمة.
- تطابق الاستجابة مع المخطط.
- الآثار الجانبية المتوقعة.
- زمن الاستجابة ضمن حد مقبول.
مثال سيئ:
status == 200
مثال أفضل:
status == 201
body.id exists
body.status == "created"
body.total == 120
response schema matches expected schema
يمكنك استخدام التحققات للتأكد من أن الاستجابة صحيحة فعلًا، وليس فقط أن الخادم أعاد ردًا ناجحًا.
4. التنظيف Cleanup
أزل البيانات التي أنشأها الاختبار أو أعد البيئة إلى حالة نظيفة.
مثال:
Cleanup:
DELETE /orders/{id}
DELETE /users/{testUserId}
إذا ترك الاختبار بيانات خلفه، فسيفشل لاحقًا بسبب تعارضات أو قيود فريدة أو حالة مشتركة مع اختبارات أخرى.
قواعد عملية لكتابة اختبارات متينة
اتبع هذه القواعد عند كتابة أي نص اختبار:
اختبر شيئًا واحدًا فقط.
فشل الاختبار يجب أن يشير إلى سبب واضح.اجعل الاختبارات مستقلة.
يجب أن تعمل بأي ترتيب، منفردة أو ضمن مجموعة.-
لا تتحقق من بيانات متقلبة.
تجنب الاعتماد على قيم مثل:- معرفات يتم توليدها عشوائيًا.
- طوابع زمنية دقيقة.
- ترتيب غير مضمون للعناصر.
- بيانات تتغير حسب البيئة.
بدلًا من ذلك، تحقق من خصائص مستقرة:
createdAt exists
createdAt is ISO date
items length > 0
status == "active"
طريقتان لكتابة نصوص اختبار API
بالنسبة لاختبار API، يوجد نهجان شائعان: code-first و visual.
النهج الأول: الاختبارات القائمة على الكود
في هذا النهج تكتب الاختبارات بلغة عامة مثل Python أو JavaScript.
مثال مبسط باستخدام JavaScript:
const res = await fetch("https://api.example.com/users", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
name: "Test User",
email: "test@example.com",
}),
});
const body = await res.json();
expect(res.status).toBe(201);
expect(body.id).toBeDefined();
expect(body.email).toBe("test@example.com");
هذا النهج مناسب عندما:
- تريد حفظ الاختبارات داخل مستودع التطبيق.
- الفريق مرتاح مع صيانة الكود.
- تحتاج إلى منطق اختبار معقد.
- تريد fixtures مخصصة وتحكمًا كاملًا في التنفيذ.
لكن تكلفته أعلى:
- كل اختبار هو كود يجب صيانته.
- ستكرر معالجة المصادقة وبناء الطلبات وتحليل الاستجابات.
- يحتاج الفريق إلى إتقان اللغة والإطار المستخدم.
النهج الثاني: الاختبارات المرئية
في النهج المرئي، تبني الاختبار داخل أداة مخصصة لاختبار API. تحدد الطلب، تضيف التحققات، وتربط عدة طلبات في سيناريو دون كتابة كود للحالات الشائعة.
تتبع أدوات مثل Apidog هذا الأسلوب.
هذا النهج مناسب عندما:
- تريد بناء الاختبارات بسرعة.
- يعمل على الاختبارات أكثر من دور داخل الفريق، مثل QA وBackend وProduct.
- لا تريد مشروعًا برمجيًا كاملًا فقط لتشغيل اختبارات API.
- تريد تقليل boilerplate.
ما زلت تستطيع استخدام كود مخصص عند الحاجة، مثل منطق شرطي أو حساب قيم أو مقارنة نتائج بين طلبات. لكن الفكرة هي أن معظم الاختبارات لا تحتاج إلى ذلك.
الاختيار ليس صحيحًا أو خاطئًا بشكل مطلق. السؤال الأهم هو: من سيصون الاختبارات؟ وهل يجب أن تعيش داخل مستودع التطبيق؟ بالنسبة لكثير من اختبارات API، النهج المرئي يعطي نتيجة أسرع وصيانة أقل.
كتابة نص برمجي لاختبار API آلي في Apidog
فيما يلي تدفق عملي لبناء اختبار API متين في Apidog.
الخطوة 1: تحديد الطلب
ابدأ بإضافة نقطة النهاية إلى Apidog. يمكنك:
- استيرادها من ملف OpenAPI.
- أو تعريفها يدويًا.
حدّد:
- HTTP method مثل
GETأوPOST. - المسار.
- الرؤوس headers.
- query parameters.
- body إذا كان الطلب يحتاجه.
مثال:
POST /users
Content-Type: application/json
Authorization: Bearer {{token}}
{
"name": "Test User",
"email": "test@example.com"
}
هذه هي مرحلة Arrange الأساسية.
الخطوة 2: إضافة بيانات الاختبار
جهّز البيانات التي تغطي الحالة التي تريد اختبارها.
مثال لحالة إيجابية:
{
"name": "Valid User",
"email": "valid@example.com"
}
ومثال لحالة سلبية:
{
"name": "",
"email": "invalid-email"
}
إذا كنت تريد اختبار عدة مدخلات بنفس المنطق، استخدم CSV أو JSON لتشغيل الاختبار عدة مرات ببيانات مختلفة. هذا هو أسلوب الاختبار القائم على البيانات، وهو أفضل من إنشاء عشرات الاختبارات المتشابهة.
مثال CSV:
name,email,expectedStatus
Valid User,valid@example.com,201
,missing-name@example.com,400
Invalid Email,invalid-email,400
الخطوة 3: كتابة التحققات
أضف تحققات واضحة لكل نتيجة مهمة.
للحالة الإيجابية، تحقق من:
status == 201
body.id exists
body.name == "Valid User"
body.email == "valid@example.com"
schema matches User schema
للحالة السلبية، لا تكتفِ بـ 400. تحقق من شكل الخطأ:
status == 400
body.error.code == "VALIDATION_ERROR"
body.error.message exists
تجنب التحقق من قيم متغيرة مثل:
body.id == "123"
body.createdAt == "2025-01-01T10:00:00Z"
واستخدم بدلًا من ذلك:
body.id exists
body.createdAt is valid datetime
الخطوة 4: تسلسل الطلبات في سيناريو
تدفقات API الحقيقية غالبًا لا تتكون من طلب واحد. مثال سيناريو كامل:
1. Login
2. Create resource
3. Read resource
4. Update resource
5. Delete resource
يمكنك تمرير قيم من خطوة إلى أخرى، مثل:
Login response -> token
Create response -> resourceId
Read request -> uses resourceId
Delete request -> uses resourceId
بهذا تختبر تدفقًا واقعيًا مع إبقاء كل خطوة واضحة.
الخطوة 5: أضف JavaScript فقط عند الحاجة
استخدم المعالجات المسبقة أو اللاحقة عندما تحتاج إلى منطق لا يمكن التعبير عنه بالتحققات المرئية.
أمثلة على الحالات المناسبة للكود:
- توليد توقيع request.
- حساب قيمة checksum.
- مقارنة بيانات بين طلبين.
- منطق شرطي خاص.
مثال منطقي بسيط:
const total = response.body.items.reduce((sum, item) => sum + item.price, 0);
pm.expect(response.body.total).to.eql(total);
اجعل الكود المخصص محدودًا. إذا كان كل اختبار يحتاج إلى سكربت طويل، فقد أصبحت الاختبارات أصعب في الصيانة.
الخطوة 6: تشغيل السيناريو وقراءة التقرير
شغّل السيناريو وتحقق من التقرير.
التقرير الجيد يجب أن يوضح:
- أي خطوة فشلت.
- أي تحقق فشل.
- القيمة المتوقعة.
- القيمة الفعلية.
- وقت الاستجابة.
- تفاصيل الطلب والاستجابة.
هذا يجعل إصلاح المشكلة أسرع، لأنك لا تبحث فقط عن “فشل الاختبار”، بل تعرف أي افتراض لم يعد صحيحًا.
الخطوة 7: أتمتة التشغيل
اربط السيناريو مع CI/CD ليعمل مع كل commit أو قبل النشر.
الاختبار الذي يعمل فقط عندما يتذكره شخص ما ليس آليًا بالكامل.
تدفق عملي:
Developer commits code
CI pipeline starts
API tests run
If tests pass -> continue deployment
If tests fail -> stop pipeline
يمكنك تنزيل Apidog وبناء أول سيناريو اختبار API لك.
الحفاظ على صحة نصوص الاختبار
مجموعة الاختبار ليست شيئًا تكتبه مرة واحدة وتنساه. مع تغير API، يجب أن تتغير الاختبارات معها.
حدّث الاختبارات مع API
عندما يتغير عقد endpoint، حدّث الاختبار في نفس commit.
مثال:
Change:
response field "username" renamed to "name"
Same commit:
update API implementation
update API schema
update test assertions
إذا بقي الاختبار يتحقق من مخطط قديم، فسيفشل لسبب غير مفيد ويقلل ثقة الفريق في مجموعة الاختبار.
تعامل مع الاختبارات المتقلبة كأخطاء
الاختبار الذي ينجح أحيانًا ويفشل أحيانًا أخطر من عدم وجود اختبار، لأنه يعلّم الفريق تجاهل اللون الأحمر.
الأسباب الشائعة:
- حالة مشتركة بين الاختبارات.
- اعتماد على ترتيب التنفيذ.
- انتظار غير كافٍ لعملية غير متزامنة.
- بيانات اختبار غير معزولة.
- تحقق من timestamp أو ID متغير.
أصلح السبب بدلًا من إعادة تشغيل الاختبار حتى ينجح.
راجع الاختبارات كما تراجع كود الإنتاج
الاختبار الضعيف يعطي شعورًا زائفًا بالأمان.
مثال اختبار ضعيف:
status == 200
مثال أفضل:
status == 200
body.user.id exists
body.user.email == expectedEmail
body.user.status == "active"
schema matches UserResponse
اجعل مراجعة الاختبارات جزءًا من مراجعة التغييرات، خصوصًا عندما تتغير العقود أو الاستجابات.
قائمة تحقق سريعة قبل اعتماد اختبار API
استخدم هذه القائمة قبل إضافة الاختبار إلى المجموعة:
[ ] يختبر سلوكًا واحدًا واضحًا
[ ] لا يعتمد على اختبار آخر
[ ] ينشئ أو يعزل بياناته
[ ] يحتوي على تحققات مفيدة
[ ] لا يتحقق من بيانات متقلبة
[ ] ينظف البيانات التي أنشأها
[ ] يمكن تشغيله محليًا وفي CI
[ ] يفشل برسالة قابلة للفهم
الأسئلة المتكررة
ما الفرق بين حالة الاختبار والنص البرمجي للاختبار؟
حالة الاختبار تصف القصد بعبارات بشرية: الإدخال، الإجراء، والنتيجة المتوقعة. النص البرمجي للاختبار هو النسخة التنفيذية التي تشغلها الآلة. الحالة هي الخطة، والنص البرمجي هو التنفيذ.
هل أحتاج إلى معرفة البرمجة لكتابة نصوص اختبار آلية؟
ليس بالضرورة لاختبار API باستخدام أداة مرئية. في Apidog، يمكنك بناء الطلبات، والتحققات، والسيناريوهات بالنقر، وتكتب الكود فقط للمنطق غير المعتاد. أما أطر العمل code-first فتتطلب مهارات برمجية.
لماذا تستمر نصوص الاختبار الخاصة بي في التعطل؟
الأسباب الشائعة هي:
- التحقق من بيانات متقلبة.
- اعتماد اختبار على حالة اختبار آخر.
- عدم تحديث الاختبارات عند تغير API.
- ترك بيانات اختبار من تشغيل سابق.
- افتراضات توقيت غير مستقرة.
ابدأ بعزل البيانات، ثم اجعل الاختبارات مستقلة، ثم حدّثها مع عقد API.
كم عدد التحققات التي يجب أن يحتوي عليها نص الاختبار الواحد؟
ما يكفي لإثبات أن النتيجة صحيحة فعلًا. غالبًا يشمل ذلك:
- كود الحالة.
- الحقول الرئيسية في body.
- المخطط.
- رسالة الخطأ للحالات السلبية.
- زمن الاستجابة عند الحاجة.
تحقق واحد من status code فقط قليل جدًا.
هل يجب أن تعيش نصوص الاختبار في مستودع التطبيق؟
في النهج code-first، غالبًا نعم، حتى يتم إصدار الاختبارات مع الكود. في النهج المرئي، تعيش الاختبارات داخل منصة الاختبار وتتزامن مع تعريف API. كلا الأسلوبين يعملان؛ الأهم هو الاتساق وسهولة الصيانة.
كيف أكتب نصوص الاختبار قبل بناء API؟
اكتبها بناءً على تصميم API أو مواصفات OpenAPI. يمكنك تعريف الطلبات والتحققات مسبقًا وتشغيلها ضد mock server إلى أن تصبح نقطة النهاية الحقيقية جاهزة. بهذه الطريقة تكون الاختبارات جاهزة عند وصول التنفيذ.
ما الفرق بين نص الاختبار ومجموعة الاختبار؟
نص الاختبار يجري فحصًا واحدًا أو يتحقق من سلوك واحد. مجموعة الاختبار هي مجموعة من النصوص التي تُشغّل معًا، غالبًا لتغطية API أو ميزة كاملة.
ما المدة المناسبة لنص الاختبار الآلي؟
يجب أن يكون قصيرًا قدر الإمكان مع الحفاظ على الأجزاء الأربعة:
Arrange
Act
Assert
Cleanup
إذا أصبح النص طويلًا، فعادةً هو يختبر أكثر من سلوك ويجب تقسيمه. سلوك واحد لكل نص يجعل الفشل أسهل في التشخيص.
Top comments (0)