Skip to content

استراتيجيات الاختبار

مقدمة

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

سيساعدك هذا الفصل على فهم الاستراتيجيات الأساسية لاختبار البرمجيات، من هرم الاختبار إلى TDD، وبناء تفكير منهجي لضمان الجودة.

ماذا ستتعلم في هذه المقالة؟

الفصلالمحتوىالمفهوم الأساسي
الفصل 1هرم الاختبارمستويات ونسب الاختبار
الفصل 2ممارسة اختبارات الوحدةكيفية كتابة اختبار جيد
الفصل 3التطوير الموجه بالاختبارات (TDD)دورة الأحمر-الأخضر-إعادة البناء
الفصل 4اختيار استراتيجية الاختبارحلول لسيناريوهات مختلفة

بعد إكمال هذا الفصل، ستفهم كيفية اختيار استراتيجية الاختبار المناسبة لمشروعك، وكتابة اختبارات ذات قيمة، وتحسين جودة تصميم الكود من خلال TDD.


0. نظرة عامة: لماذا نحتاج الاختبارات المؤتمتة؟

تخيل أنك مهندس بناء. في كل مرة تعدل المخططات، لا تتسلق كل طابق بنفسك للتحقق من سلامة الهيكل — بل تعتمد على نظام كشف مؤتمت. اختبارات البرمجيات هي "نظام الكشف الهيكلي" في عالم الكود.

قيمة الاختبارات المؤتمتة

  • الحماية من الانحدار: عند تعديل الميزة A، يُكشف تلقائيًا ما إذا كانت B وC وD متأثرة
  • الثقة في إعادة البناء: الكود المغطى بالاختبارات يعطي راحة أكبر عند إعادة البناء
  • توثيق حيّ: الاختبارات الجيدة هي أفضل دليل استخدام
  • التغذية الراجعة السريعة: معرفة ما إذا كان الكود صحيحًا في ثوانٍ، بدلاً من اكتشاف المشاكل بعد النشر

1. هرم الاختبار: مستويات ونسب الاختبار

1.1 الهرم ذو الثلاث مستويات

هرم الاختبار الذي اقترحه مايك كون هو النموذج الكلاسيكي لاستراتيجية الاختبار. يخبرنا أن الأنواع المختلفة من الاختبارات يجب أن تكون بنسب مختلفة.

من خلال المكون التفاعلي التالي، انقر على كل مستوى من الهرم للتعرف على خصائص كل نوع من الاختبارات:

Interactive test pyramid - click each layer for details
🖥️E2E tests
🔗Integration tests
🧪Unit tests
Higher: slower, more expensive, closer to usersLower: faster, more numerous, closer to code

1.2 لماذا شكل الهرم؟

شكل الهرم يعكس مفاضلة جوهرية: التوازن بين السرعة والواقعية.

  • المستوى السفلي (اختبارات الوحدة): سريعة جدًا، الأكثر عددًا، الأقل تكلفة، لكنها تتحقق فقط من القطع الفردية
  • المستوى المتوسط (اختبارات التكامل): سرعة معتدلة، عدد معتدل، تتحقق من التعاون بين القطع
  • المستوى العلوي (اختبارات E2E): الأقرب للمستخدم الحقيقي، لكن بطيئة، مكلفة في الصيانة، وعرضة للفشل بسبب مشاكل البيئة

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


2. ممارسة اختبارات الوحدة

2.1 ما الذي يجعل اختبار الوحدة جيدًا؟

اختبارات الوحدة الجيدة تتبع مبدأ FIRST:

المبدأالمعنىالشرح
Fastسريعيُنجز في أجزاء من الثانية، والمطورون مستعدون لتشغيله بشكل متكرر
Independentمستقلالاختبارات لا تعتمد على بعضها، يمكن تشغيلها بشكل فردي
Repeatableقابل للتكرارالنتائج متسقة في أي بيئة
Self-validatingذاتي التحققالنتيجة واضحة نجاح/فشل، بدون حاجة لحكم بشري
Timelyفي الوقت المناسبتُكتب في نفس وقت كتابة الكود (أو قبله)

2.2 بنية الاختبار: نمط AAA

يجب أن يكون لكل اختبار بنية ثلاثية الأجزاء واضحة:

javascript
test('يجب أن يحسب السعر مع الضريبة بشكل صحيح', () => {
  // Arrange (ترتيب) — إعداد بيانات الاختبار
  const price = 100
  const taxRate = 0.13

  // Act (تنفيذ) — استدعاء الدالة قيد الاختبار
  const result = calculateTotalWithTax(price, taxRate)

  // Assert (تأكيد) — التحقق من النتيجة
  expect(result).toBe(113)
})

2.3 ماذا نختبر؟ وماذا لا نختبر؟

ما يجب اختباره:

  • منطق الأعمال الأساسي (حساب الأسعار، التحقق من الصلاحيات، تحويل البيانات)
  • الشروط الحدية (قيم فارغة، صفر، أعداد سالبة، أعداد كبيرة جدًا)
  • مسارات معالجة الأخطاء

ما لا يحتاج لاختبار:

  • التنفيذ الداخلي لمكتبات الطرف الثالث
  • getters/setters البسيطة
  • وظائف الإطار نفسه (مثل نظام Vue التفاعلي)

3. TDD: التطوير الموجه بالاختبارات

3.1 دورة الأحمر-الأخضر-إعادة البناء

جوهر TDD (Test-Driven Development) هو دورة بسيطة: اكتب الاختبار أولاً، ثم اكتب التنفيذ، وأخيرًا أعِد البناء.

من خلال المكون التفاعلي التالي، جرّب الدورة الكاملة لـ TDD:

TDD red-green-refactor cycle - click “Next” to advance
🔴Red
🟢Green
🔵Refactor
Step 1 / 5🔴 Red - write a failing test first
Requirement: implement add(a, b). The first TDD step is not implementation, but writing a test.
add.test.js
test('add(1, 2) should return 3', () => {
  expect(add(1, 2)).toBe(3)
})
❌ Test failed - add is not defined

3.2 القواعد الثلاث لـ TDD

  1. لا تكتب أي كود إنتاجي إلا لجعل اختبار فاشل ينجح
  2. اكتب فقط كود الاختبار الكافي ليفشل (عدم التجميع يُحسب أيضًا كفشل)
  3. اكتب فقط كود الإنتاج الكافي ليجعل الاختبار ينجح

3.3 القيمة الحقيقية لـ TDD

قيمة TDD لا تكمن فقط في "كتابة الاختبارات أولاً"، بل في أنها تجبرك على التفكير في تصميم الواجهات. عندما تكتب الاختبار أولاً، فأنت تفكر من منظور "المستخدم": ما المعاملات التي يجب أن تتلقاها هذه الدالة؟ ما النتيجة التي يجب أن تعيدها؟ هذا يقود بشكل طبيعي إلى تصميم API أفضل.

TDD ليس رصاصة فضية

TDD مناسب للكود الكثيف بالمنطق (الخوارزميات، قواعد الأعمال، تحويل البيانات)، لكن بالنسبة لتخطيط الواجهة والنماذج الأولية الاستكشافية، فإن فرض TDD قد يبطئ التطور. المفتاح هو فهم فلسفته وتطبيقها بمرونة.


4. اختيار استراتيجية الاختبار

4.1 تركيز الاختبار حسب نوع المشروع

نوع المشروعتركيز الاختبارالنسبة المقترحة
مكتبة/SDKاختبارات الوحدة بشكل أساسي90% وحدة + 10% تكامل
خدمة APIاختبارات التكامل بشكل أساسي30% وحدة + 60% تكامل + 10% E2E
تطبيق ويبتوزيع متوازن50% وحدة + 30% تكامل + 20% E2E
MVP/نموذج أوليE2E للمسارات الحرجةاختبارات أساسية قليلة تكفي

4.2 أدوات الاختبار الشائعة

الأداةالنوعحالة الاستخدام
Vitestوحدة/تكاملالخيار الأول لمشاريع Vite، متوافق مع API لـ Jest
Jestوحدة/تكاملالأكثر شعبية في نظام Node.js البيئي
PlaywrightE2Eمتعدد المتصفحات، من مايكروسوفت
CypressE2Eتجربة تطوير جيدة، سهل التصحيح
Testing Libraryاختبار المكوناتاختبار مكونات الواجهة من منظور المستخدم

5. دعم الذكاء الاصطناعي: تحسين كفاءة الاختبار بالنماذج اللغوية

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

5.1 توليد اختبارات الوحدة

Prompt:

اكتب اختبارات وحدة للدالة التالية باستخدام إطار Vitest. المتطلبات:
1. اتباع نمط AAA (Arrange-Act-Assert)
2. تغطية المسار الطبيعي والشروط الحدية ومسارات الأخطاء
3. يجب أن يكون لكل حالة اختبار وصف واضح

[الصق كود الدالة الخاصة بك]

5.2 اكتشاف الشروط الحدية

Prompt:

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

[الصق كود الدالة الخاصة بك]

5.3 توليد اختبارات من المتطلبات (مساعدة TDD)

Prompt:

أريد تنفيذ وحدة سلة تسوق بالمتطلبات التالية:
- إضافة منتجات، حذف منتجات، تعديل الكميات
- حساب المجموع تلقائيًا (بما في ذلك الخصومات)
- عرض خطأ عند عدم كفاية المخزون

باتباع نهج TDD، اكتب حالات الاختبار أولاً (بدون تنفيذ)،
باستخدام Vitest، مع تغطية جميع السيناريوهات الأساسية.

نصائح استخدام الذكاء الاصطناعي

تحقق من أن تأكيدات الاختبارات التي ينشئها الذكاء الاصطناعي ذات معنى — تجنب اختبارات عديمة الفائدة مثل expect(true).toBe(true). الاختبار الجيد يجب أن يفشل فعلاً عندما يكون هناك خطأ في الكود.


6. الخلاصة

  1. هرم الاختبار: الكثير في الأسفل، القليل في الأعلى، موازنة السرعة والواقعية
  2. اختبارات الوحدة: اتبع مبدأ FIRST ونمط AAA، اختبر المنطق الأساسي
  3. TDD: دورة الأحمر-الأخضر-إعادة البناء، استخدم الاختبارات لتوجيه التصميم
  4. اختيار الاستراتيجية: حسب نوع المشروع ومرحلته، اختر النسبة المناسبة من الاختبارات

تأمل أخير

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


قراءات إضافية

  • كتاب كلاسيكي: Test-Driven Development لكينت بيك هو العمل التأسيسي لـ TDD.
  • دليل عملي: حاول كتابة اختبارات لمشروع صغير باستخدام Vitest، وتجربة عملية الاختبار من الصفر.
  • أنماط الاختبار: تعرف على الفرق بين Mock وStub وSpy وسيناريوهات استخدامها.
  • التكامل المستمر: ادمج الاختبارات في خط أنابيب CI/CD الخاص بك لتشغيلها تلقائيًا مع كل التزام.