البرمجة

اختبار الوحدات في Node.js

اختبار الوحدات البرمجية باستخدام Mocha و Assert في Node.js

يعد اختبار الوحدات (Unit Testing) من الركائز الأساسية في عملية تطوير البرمجيات الحديثة، إذ يضمن سلوك الوحدات البرمجية الصغيرة (مثل الدوال أو الوحدات النمطية) بشكل صحيح ومنفصل عن بقية النظام. ومع تزايد اعتماد المطورين على بيئة Node.js لبناء تطبيقات متنوعة، برزت أدوات قوية تسهّل تنفيذ هذا النوع من الاختبارات، ومن أبرزها مكتبة Mocha للإطار العام للاختبار، وAssert كوحدة مدمجة مع Node.js للتحقق من صحة النتائج. يسلط هذا المقال الضوء على المفاهيم الأساسية لاختبار الوحدات، دور Mocha وAssert في هذا السياق، وكيفية استخدامهما بفعالية في مشاريع Node.js.


أهمية اختبار الوحدات في تطوير البرمجيات

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

  • يتم الكشف عن الأخطاء مبكرًا في دورة حياة التطوير.

  • يتحسن تصميم الكود من خلال تشجيع كتابة وحدات صغيرة ومترابطة بشكل ضعيف.

  • تزداد الثقة عند إجراء التغييرات أو التحديثات في الشيفرة.

  • يتم تسهيل عملية دمج الكود في فرق التطوير متعددة الأعضاء.

  • تُسرّع وتيرة النشر خصوصًا عند الاعتماد على تكامل مستمر (CI).

في Node.js، حيث يتم بناء الكثير من التطبيقات عالية الأداء والمعتمدة على الأحداث، يصبح من الضروري اختبار كل وحدة على حدة لضمان توافقها مع السيناريوهات الحقيقية.


لمحة عامة عن Mocha و Assert

مكتبة Mocha

Mocha هي إطار لاختبار الوحدات يعمل مع Node.js، وتتميز بـ:

  • بساطة التركيب والاستخدام.

  • دعم تنفيذ الاختبارات غير المتزامنة (Asynchronous Testing).

  • هيكلية مرنة باستخدام describe() و it() لتنظيم الحالات الاختبارية.

  • تكامل سهل مع أدوات أخرى مثل Chai وSinon.

  • خيارات تقارير متعددة لتقديم مخرجات مفيدة.

وحدة Assert

Assert هي وحدة مدمجة في Node.js وتُستخدم للتحقق من صحة القيم المتوقعة دون الحاجة لتثبيت مكتبات إضافية. توفر واجهات تحقق متنوعة تشمل:

  • assert.strictEqual(): للمقارنة الصارمة.

  • assert.deepStrictEqual(): لمقارنة الكائنات بعمق.

  • assert.throws(): لاختبار الأخطاء المتوقع وقوعها.


إعداد بيئة العمل

لبدء استخدام Mocha وAssert، يجب أولًا تجهيز بيئة Node.js وتثبيت Mocha كمكتبة تطوير:

bash
mkdir mocha-test-example cd mocha-test-example npm init -y npm install --save-dev mocha

بعدها، يمكن إنشاء مجلد test/ داخل المشروع لتخزين ملفات الاختبار.


بنية اختبار الوحدات باستخدام Mocha و Assert

1. كتابة وحدة وظيفية

لنبدأ بكتابة دالة بسيطة في ملف math.js:

js
// math.js function add(a, b) { return a + b; } function divide(a, b) { if (b === 0) throw new Error("Division by zero"); return a / b; } module.exports = { add, divide };

2. إنشاء ملف الاختبار

داخل مجلد test/، ننشئ ملف math.test.js يحتوي على اختبارات للدوال السابقة:

js
// test/math.test.js const assert = require('assert'); const { add, divide } = require('../math'); describe('Math Module', function () { describe('add()', function () { it('should return 5 when adding 2 + 3', function () { assert.strictEqual(add(2, 3), 5); }); it('should return -1 when adding -3 + 2', function () { assert.strictEqual(add(-3, 2), -1); }); }); describe('divide()', function () { it('should return 2 when dividing 4 by 2', function () { assert.strictEqual(divide(4, 2), 2); }); it('should throw error when dividing by 0', function () { assert.throws(() => divide(5, 0), /Division by zero/); }); }); });

3. تشغيل الاختبارات

يمكن تشغيل Mocha باستخدام الأمر التالي بعد تعديل ملف package.json:

json
"scripts": { "test": "mocha" }

ثم تشغيل:

bash
npm test

ستظهر نتائج الاختبارات مع توضيح النجاح أو الفشل لكل حالة اختبارية.


التعامل مع العمليات غير المتزامنة

واحدة من الميزات البارزة في Mocha هي دعمها للاختبارات غير المتزامنة، وهي ميزة ضرورية في بيئة Node.js المعتمدة على الـ Callback وPromises.

باستخدام Callback

js
it('should wait 1 second and pass', function (done) { setTimeout(() => { assert.strictEqual(1, 1); done(); }, 1000); });

باستخدام Promise

js
it('should resolve the promise correctly', function () { return Promise.resolve().then(() => { assert.strictEqual(2 * 2, 4); }); });

باستخدام async/await

js
it('should support async/await', async function () { const result = await Promise.resolve(10); assert.strictEqual(result, 10); });

تنظيم اختبارات الوحدة بشكل فعّال

استخدام ملفات متعددة

من الأفضل تنظيم الاختبارات في ملفات متعددة حسب وحدة العمل، مثل:

lua
project/ ├── math.js └── test/ ├── math.test.js └── string.test.js

استخدام Hooks

توفر Mocha دوالًا لإعداد البيانات أو تنظيفها قبل أو بعد كل اختبار أو مجموعة اختبارات:

js
before(() => { // تنفيذ قبل جميع الاختبارات }); beforeEach(() => { // تنفيذ قبل كل اختبار فردي }); afterEach(() => { // تنفيذ بعد كل اختبار فردي }); after(() => { // تنفيذ بعد جميع الاختبارات });

مقارنة بين Assert ومكتبات تحقق أخرى

رغم أن وحدة Assert تؤدي الغرض في معظم الحالات، إلا أن بعض المطورين يفضلون استخدام مكتبات تحقق خارجية مثل Chai بسبب تعبيراتها المرنة وقراءتها الطبيعية.

الخاصية Assert (Node.js) Chai (خارجية)
الحاجة للتثبيت لا نعم
أسلوب الكتابة تقليدي (Function) وصفي (should/expect)
دعم أنواع تحقق متنوعة محدود واسع
التوافق مع Mocha ممتاز ممتاز

نصائح لتحسين اختبارات Mocha

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

  • سَمّ الاختبارات بدقة: يجب أن تكون أسماء describe و it واضحة وتعبر عن السلوك المُختبر.

  • تجنب التداخل الكبير بين الاختبارات: حافظ على استقلالية كل حالة اختبارية.

  • استخدم تغطية الاختبار (Coverage): من خلال أدوات مثل nyc للحصول على قياسات حول مدى تغطية الكود بالاختبارات.

  • دمج Mocha في CI/CD: لدمج الاختبارات ضمن دورة النشر التلقائية.


جدول يوضح الفروقات بين أنواع اختبارات البرامج

النوع الهدف الأمثلة الأدوات المناسبة
اختبار الوحدة اختبار دوال أو وحدات صغيرة التحقق من دالة add() Mocha + Assert
اختبار التكامل اختبار تفاعل مكونات النظام التحقق من تكامل قاعدة البيانات Mocha + Supertest
اختبار النظام الكامل اختبار النظام من وجهة نظر المستخدم اختبار تسجيل المستخدم Cypress, Selenium
اختبار الأداء قياس استجابة النظام تحت الضغط اختبار استجابة API Artillery, JMeter

التعامل مع الأخطاء واستكشاف المشكلات

عند فشل اختبار، ينبغي مراجعة النقاط التالية:

  • القيم المتوقعة مقابل القيم الحقيقية.

  • هل الدالة تتعامل مع الحالات الحدية كما يجب؟.

  • الاختبارات غير المتزامنة: هل تم استخدام done() أو await بشكل صحيح؟.

  • هل توجد آثار جانبية ناتجة عن اختبارات سابقة؟.

Mocha يعرض Stack Trace مفيد لتحديد مكان الخطأ بدقة. يمكن أيضًا استخدام خيار --timeout لضبط المدة المسموح بها لكل اختبار.


التكامل مع أدوات التغطية (Coverage)

أداة nyc (الواجهة الخاصة بـ Istanbul) تُستخدم لقياس مدى تغطية الشيفرة البرمجية بالاختبارات. لتثبيتها:

bash
npm install --save-dev nyc

تعديل السكريبت:

json
"scripts": { "test": "nyc mocha" }

تشغيل:

bash
npm test

ستظهر تغطية لكل ملف على مستوى السطور والفروع والشروط.


خلاصة المفاهيم الأساسية

اختبار الوحدات باستخدام Mocha وAssert في Node.js يمثل خطوة جوهرية نحو تطوير برامج موثوقة وقابلة للصيانة. من خلال بنية واضحة لاختبارات منظمة، ودعم كامل للأنماط المتزامنة وغير المتزامنة، وتكامل مع أدوات التغطية والدمج المستمر، يمكن ضمان الجودة البرمجية ومواكبة المتطلبات الحديثة. توفر Mocha إطارًا قويًا ومنفتحًا يمكن تخصيصه ليتلاءم مع أي مشروع تقريبًا، بينما تقدم وحدة Assert أدوات بسيطة وفعالة لتأكيد السلوكيات المتوقعة.


المراجع:

  1. Mocha Official Documentation

  2. Node.js Assert Module Docs