الـ doubles · فصل ٤

Sinon — راقب وبدّل السلوك

fake · spy · stub · sandbox · restore
🎯 الهدف: تفرّق بين fake وspy وstub، وتمنع test من تلويث اللي بعده.

Sinon مش runner

Sinon مكتبة test doubles. تركبها غالبًا جنب Mocha + Chai، لكن تقدر تستخدمها مع أي runner. Jest وVitest عندهم بدائل مدمجة (jest.fn وvi.fn)، فإضافة Sinon ليهم محتاجة سبب واضح.

Fake وSpy وStub

Fake

دالة بديلة بسيطة بتحدد سلوكها وبتسجل calls. Sinon بيوصي بالـ fakes للكود الجديد في أغلب الحالات.

const send = sinon.fake.resolves({ id: 7 });
Spy

يراقب دالة حقيقية: اتنادت كام مرة وبأنهي arguments وإيه اللي رجع. لو لفّ method حقيقية، الأصل بيتنفذ.

const spy = sinon.spy(logger, "info");

الـ stub يستبدل behavior: يرجّع قيمة، يرمي error، أو يتصرف بشكل مختلف كل call. الأصل مش بيتنفذ.

const stub = sinon.stub(gateway, "charge");stub.onFirstCall().rejects(new Error("timeout"));stub.onSecondCall().resolves({ ok: true });

اختبر error path

checkout.test.js
import { expect } from "chai";import sinon from "sinon";import { checkout } from "../src/checkout.js";describe("checkout", () => {  afterEach(() => sinon.restore());  it("يرجع رسالة مفهومة لو الدفع وقع", async () => {    sinon.stub(gateway, "charge").rejects(new Error("timeout"));    const result = await checkout(gateway);    expect(result).to.deep.equal({ ok: false, reason: "payment-unavailable" });    sinon.assert.calledOnce(gateway.charge);  });});

الـ sandbox ينضّف وراك

لو عندك doubles كتير، sandbox تجمعهم:

const sandbox = sinon.createSandbox();afterEach(() => sandbox.restore());it("يبعت event", () => {  const publish = sandbox.stub(bus, "publish").resolves();  // شغّل السلوك  sinon.assert.calledWith(publish, "order.created");});

إمتى بلاش stub؟

لو تقدر تمرّر dependency كدالة عادية، fake مستقلة أبسط من ترقيع module عالمي:

const sendEmail = sinon.fake.resolves();await registerUser({ email: "a@b.com" }, { sendEmail });sinon.assert.calledOnce(sendEmail);

ده كمان يحسن تصميم production: dependency واضحة بدل import مخفي.

خلّصت الفصل لما

🧠 اختبر نفسك
١) عايز تعرف logger.info اتنادت، ومحتاج الأصل يشتغل. تستخدم إيه؟
Spy.
٢) عايز payment gateway يرمي timeout متحكم فيه. تستخدم إيه؟
Stub أو fake ممرّرة كـ dependency. المهم تمنع الاتصال الحقيقي وتحدد السلوك.
٣) ليه sandbox مفيدة؟
بتجمع الـ doubles وبتعمل restore لهم مع بعض، فتمنع تسريب الحالة بين الاختبارات.