Sinon لجافا سكريبت (Node.js): دليل شامل مع أمثلة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

Sinon لجافا سكريبت (Node.js): دليل شامل مع أمثلة

1. ما هي Sinon ولماذا نحتاجها؟

Sinon.js هي مكتبة قوية لجافا سكريبت توفر كائنات اختبارية مستقلة: جواسيس (spies)، وهمية (stubs)، ومحاكاة (mocks). لا تعتمد على إطار اختبار محدد (Mocha، Jest، Jasmine وغيرها) ويمكن استخدامها مع أي منها. الهدف الرئيسي لـ Sinon هو عزل الكود المختبر عن التبعيات الخارجية (قواعد البيانات، API، نظام الملفات، المؤقتات)، مما يسمح بالتحقق من سلوك الدوال في بيئة محكومة.

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

تحظى المكتبة بشعبية خاصة في نظام Node.js البيئي، حيث يكون اختبار الوحدات أمرًا بالغ الأهمية. تسمح لك باختبار الدوال دون إجراء طلبات HTTP حقيقية، أو الوصول إلى قاعدة البيانات، أو انتظار المؤقتات. هذا يسرع تنفيذ الاختبارات بعشرات المرات ويجعلها حتمية.

2. التثبيت

يتم تثبيت Sinon عبر npm. لـ Node.js، نفذ الأمر التالي:

npm install sinon --save-dev

إذا كنت تستخدم TypeScript، قم أيضًا بتثبيت الأنواع:

npm install sinon @types/sinon --save-dev

للاستخدام في المتصفح، يمكنك تضمين نسخة CDN:

<script src="https://cdn.jsdelivr.net/npm/sinon@latest/pkg/sinon.js"></script>

بعد التثبيت، قم باستيراد المكتبة في ملف الاختبار الخاص بك:

const sinon = require('sinon'); // CommonJS
// أو
import sinon from 'sinon'; // ES Modules

3. بداية سريعة — مثال عملي بسيط

لننظر إلى مثال بسيط: دالة تستدعي رد اتصال مع تحية. نريد التحقق من أن رد الاتصال تم استدعاؤه بالوسيطة الصحيحة.

const sinon = require('sinon');

// الدالة التي نختبرها
function greet(name, callback) {
  callback(`مرحبًا، ${name}!`);
}

// اختبار باستخدام الجاسوس (spy)
const callbackSpy = sinon.spy();
greet('أحمد', callbackSpy);

console.log(callbackSpy.calledOnce);    // true
console.log(callbackSpy.calledWith('مرحبًا، أحمد!')); // true

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

4. الدوال/الطرق/الفئات الأساسية

4.1. sinon.spy() — الجاسوس (Spy)

التوقيع: sinon.spy([object], [method]) أو sinon.spy([func])

الوظيفة: ينشئ جاسوسًا يسجل معلومات حول استدعاءات الدالة: عدد الاستدعاءات، الوسائط، السياق، القيمة المُعادة. يمكنه تغليف دالة موجودة أو استبدال طريقة لكائن.

مثال:

const user = {
  setName: function(name) { this.name = name; }
};

const spy = sinon.spy(user, 'setName');
user.setName('خالد');

console.log(spy.calledOnce);      // true
console.log(spy.calledWith('خالد')); // true
console.log(spy.firstCall.args);  // ['خالد']

spy.restore(); // من الضروري استعادة الطريقة الأصلية

4.2. sinon.stub() — الوهمية (Stub)

التوقيع: sinon.stub([object], [method])

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

مثال:

const database = {
  getUser: function(id) { /* منطق حقيقي */ }
};

const stub = sinon.stub(database, 'getUser');
stub.withArgs(1).returns({ id: 1, name: 'سارة' });
stub.withArgs(2).throws(new Error('المستخدم غير موجود'));

console.log(database.getUser(1)); // { id: 1, name: 'سارة' }
console.log(database.getUser(2)); // يرمي خطأ

stub.restore(); // استعادة الدالة الأصلية

4.3. sinon.mock() — المحاكاة (Mock)

التوقيع: sinon.mock(object)

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

مثال:

const logger = {
  log: function(message) { /* منطق حقيقي */ },
  warn: function(message) { /* منطق حقيقي */ }
};

const mock = sinon.mock(logger);
mock.expects('log').once().withArgs('تم بدء العملية');
mock.expects('warn').never();

// تنفيذ الكود الذي يستخدم logger
logger.log('تم بدء العملية');

mock.verify(); // يتحقق من أن التوقعات قد تحققت
mock.restore(); // استعادة الكائن الأصلي

4.4. sinon.useFakeTimers() — المؤقتات الوهمية

التوقيع: sinon.useFakeTimers([now])

الوظيفة: يستبدل الدوال الزمنية العالمية (setTimeout، setInterval، Date.now) بإصدارات وهمية يمكن التحكم بها. يسمح بتقديم الوقت يدويًا دون انتظار حقيقي.

مثال:

const clock = sinon.useFakeTimers();

let callbackCalled = false;
setTimeout(() => { callbackCalled = true; }, 1000);

console.log(callbackCalled); // false
clock.tick(1000); // تقديم الوقت بمقدار 1000 مللي ثانية
console.log(callbackCalled); // true

clock.restore(); // استعادة المؤقتات الحقيقية

4.5. sinon.fake() — الدالة الوهمية

التوقيع: sinon.fake([behavior])

الوظيفة: ينشئ دالة وهمية بسيطة تسجل استدعاءاتها. أبسط من الجاسوس، وتستخدم عندما تحتاج فقط إلى دالة بديلة دون ميزات إضافية.

مثال:

const fakeCallback = sinon.fake.returns('تم بنجاح');
console.log(fakeCallback()); // 'تم بنجاح'
console.log(fakeCallback.calledOnce); // true

4.6. sinon.match() — مطابقة الوسائط

التوقيع: sinon.match(value) أو sinon.match(predicate)

الوظيفة: يوفر طرقًا مطابقة مرنة للوسائط في التأكيدات. يمكنك مطابقة أي قيمة، أو كائن بخصائص محددة، أو استخدام دالة شرط.

مثال:

const spy = sinon.spy();
spy({ name: 'أحمد', age: 30 });

console.log(spy.calledWith(sinon.match({ name: 'أحمد' }))); // true
console.log(spy.calledWith(sinon.match.has('age', 30))); // true

5. أفضل الممارسات والنصائح

  • استخدم restore() دائمًا: بعد كل اختبار، استخدم spy.restore() أو stub.restore() أو mock.restore() لاستعادة الدوال الأصلية. استخدم sinon.restore() لاستعادة كل شيء دفعة واحدة.
  • تجنب الإفراط في استخدام المحاكاة: استخدم الجواسيس والوهمية عندما يكون ذلك كافيًا. المحاكاة مناسبة للتفاعلات المعقدة.
  • اختبر السلوك وليس التنفيذ: ركز على ما تفعله الدالة، وليس كيف تفعله. تجنب اختبار التفاصيل الداخلية.
  • استخدم المؤقتات الوهمية للاختبارات الزمنية: بدلاً من استخدام setTimeout الحقيقي، استخدم sinon.useFakeTimers() لتسريع الاختبارات.
  • اجمع مع إطار اختبار: استخدم Sinon مع Mocha أو Jest أو Jasmine للحصول على تأكيدات وتقارير أفضل.

6. الخلاصة

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

توصيات