أهلاً بك في هذا الدرس!
قبل أن نغوص في عالم اختبارات الوحدات (Unit Testing) ونبدأ في كتابة الأكواد الخاصة بها، نحتاج إلى شيء ملموس لنعمل عليه. فكما لا يمكن لميكانيكي السيارات تعلم حرفته بدون سيارة ليفككها ويصلحها، لا يمكننا تعلم كتابة الاختبارات بفعالية بدون وجود كود برمجي لاختباره.
في هذا الدرس، سنقوم بإعداد مشروع بسيط جدًا سيكون بمثابة "صندوق الرمل" أو "Playground" الخاص بنا طوال هذه الدورة. سنكتب معًا بعض الدوال البرمجية (Functions) التي تحاكي وظائف بسيطة في تطبيق تجارة إلكترونية خيالي. هذا المشروع هو الأساس الذي سنبني عليه كل مفاهيم الاختبار التي سنتعلمها في الدروس القادمة.

ما هو المشروع الذي سنعمل عليه؟
مشروعنا سيكون عبارة عن مكتبة أدوات صغيرة (Utility Library) لتطبيق تجارة إلكترونية. لن نبني واجهات مستخدم أو نتعامل مع قواعد بيانات حقيقية، بل سنركز حصريًا على كتابة الدوال المنطقية (Business Logic) التي يمكن اختبارها بشكل منفصل.
لماذا اخترنا هذا النوع من المشاريع؟
- سهولة الفهم: فكرة التجارة الإلكترونية مألوفة للجميع، مما يجعل فهم وظائف الدوال مثل
calculateDiscountأوvalidateUsernameأمرًا بديهيًا. - تنوع الحالات: يتيح لنا هذا المشروع كتابة أنواع مختلفة من الدوال: دوال حسابية، دوال للتحقق من صحة المدخلات (Validation)، وحتى دوال غير متزامنة (Asynchronous) تحاكي جلب البيانات من الشبكة.
- التركيز على الهدف: من خلال تجنب تعقيدات الواجهات الأمامية أو الخلفية، يمكننا تركيز كل طاقتنا على الهدف الأساسي للدورة: إتقان اختبارات الوحدات.
هيكل المشروع
سنبدأ بهيكل بسيط للغاية. كل ما نحتاجه هو مجلد للمشروع، وبداخله مجلد للكود المصدري src وملف package.json لإدارة الحزم.
ecommerce-utils/
├── src/
│ └── main.js
└── package.jsonecommerce-utils/: هذا هو المجلد الرئيسي لمشروعنا.src/: هذا المجلد سيحتوي على كل الأكواد البرمجية التي سنكتبها.src/main.js: الملف الذي سنكتب فيه دوالنا الأساسية.package.json: الملف القياسي لأي مشروع Node.js، يحتوي على معلومات عن المشروع والاعتماديات (Dependencies).
تهيئة المشروع
الآن، دعنا نقم بإنشاء هذا الهيكل خطوة بخطوة. افتح الطرفية (Terminal) في نظامك واتبع الأوامر التالية:
إنشاء مجلد المشروع والتوجه إليه:
تهيئة مشروع Node.js جديد:
إنشاء مجلد وملف الكود المصدري:
mkdir ecommerce-utils
cd ecommerce-utilsnpm init -ymkdir src
touch src/main.jsإذا كنت تستخدم نظام Windows، يمكنك إنشاء المجلد والملف يدويًا عبر مستكشف الملفات.
الآن، يجب أن يبدو ملف package.json الخاص بك مشابهًا لهذا (قد تختلف بعض التفاصيل البسيطة):
{
"name": "ecommerce-utils",
"version": "1.0.0",
"description": "",
"main": "src/main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}رائع! لقد أصبح هيكل مشروعنا جاهزًا. حان الوقت الآن لإضافة بعض اللحم على العظام وكتابة الدوال التي سنختبرها.
الدوال الأساسية في المشروع
افتح ملف src/main.js في محرر الأكواد المفضل لديك وأضف الكود التالي. هذه هي الدوال التي ستكون محور تركيزنا في الدروس القادمة.
// src/main.js
/**
* Calculates the final price after applying a discount.
* @param {number} price - The original price.
* @param {number} discountPercentage - The discount percentage (0-100).
* @returns {number|string} The discounted price or an error message if inputs are invalid.
*/
export function calculateDiscount(price, discountPercentage) {
if (typeof price !== 'number' || price <= 0) {
return 'Invalid price';
}
if (typeof discountPercentage !== 'number' || discountPercentage < 0 || discountPercentage > 100) {
return 'Invalid discount percentage';
}
const discountAmount = (price * discountPercentage) / 100;
return price - discountAmount;
}
/**
* Validates a username based on specific rules.
* Rules: 3 to 15 characters, alphanumeric only.
* @param {string} username - The username to validate.
* @returns {boolean} True if the username is valid, false otherwise.
*/
export function validateUsername(username) {
if (typeof username !== 'string') return false;
if (username.length < 3 || username.length > 15) {
return false;
}
const pattern = /^[a-zA-Z0-9]+$/;
return pattern.test(username);
}
// Mock database of products for demonstration
const products = [
{ id: 1, name: 'Laptop', price: 1200 },
{ id: 2, name: 'Mouse', price: 25 },
{ id: 3, name: 'Keyboard', price: 75 },
];
/**
* Fetches a product by its ID asynchronously.
* @param {number} productId - The ID of the product to fetch.
* @returns {Promise<object|undefined>} A promise that resolves with the product object or undefined if not found.
*/
export function getProduct(productId) {
return new Promise((resolve) => {
// Simulate a network delay to mimic a real API call
setTimeout(() => {
const product = products.find(p => p.id === productId);
resolve(product);
}, 50);
});
}دعنا نلقي نظرة سريعة على هذه الدوال وما يجعلها مثيرة للاهتمام من منظور الاختبار:
calculateDiscount: دالة حسابية بحتة (Pure Function). تأخذ مدخلات رقمية وتعيد مخرجات بناءً على عملية حسابية. سنستخدمها لتعلم أساسيات التأكيدات (Assertions) واختبار الحالات الإيجابية والسلبية (Positive/Negative Testing) والحالات الحدية (Boundary Testing).validateUsername: دالة للتحقق من صحة السلاسل النصية. مثالية لتعلم كيفية اختبار القواعد المختلفة، مثل طول السلسلة والمحارف المسموح بها باستخدام التعابير النمطية (Regular Expressions).getProduct: دالة غير متزامنة (Asynchronous) تعيدPromise. هذه الدالة تحاكي طلبًا لجلب بيانات من خادم. ستكون بوابتنا لتعلم كيفية اختبار الأكواد غير المتزامنة، وهو تحدٍ شائع في تطوير الويب الحديث.
لماذا لا توجد اختبارات بعد؟
قد تتساءل: "أين هي الاختبارات؟" هذا سؤال ممتاز! الهدف من هذا الدرس هو فقط إعداد المسرح. لقد قمنا الآن بتأسيس أرضية مشتركة، وهي الكود الذي سنقوم باختباره. فمن غير المنطقي أن نتحدث عن كيفية اختبار شيء لا وجود له بعد.
لا تقلق، في الدروس التالية مباشرة، سنبدأ في إعداد بيئة الاختبار الخاصة بنا وسنكتب أول اختباراتنا لهذه الدوال تحديدًا. ستشاهد بنفسك كيف يمكننا التحقق من كل سطر من هذه الأكواد لضمان عملها بالشكل الصحيح.
الخلاصة
لقد قمنا بعمل رائع في هذا الدرس! أصبح لدينا الآن:
- مشروع JavaScript بسيط ومنظم.
- مجموعة من الدوال الواضحة التي تغطي سيناريوهات مختلفة.
- أساس متين سنبني عليه رحلتنا في تعلم اختبار الوحدات.
أنت الآن جاهز للانتقال إلى الخطوة التالية والمثيرة. في الدرس القادم، سنغوص في المفاهيم النظرية ونعرف ما هو اختبار الوحدات (Unit Testing) بالضبط ولماذا هو بهذه الأهمية. هيا بنا!

إرسال تعليق