تخطَّ إلى المحتوى
AzLearn

Mocks و Fakes

Mocks and Fakes

مفهوم ~19 دقيقة المستوى: متوسط

Mocks و Fakes

عندما تعتمد دالة على API أو قاعدة بيانات أو وقت النظام، يصبح الاختبار أصعب. الحل هو تعريف interface للتبعية، ثم تمرير fake في الاختبار. TypeScript يضمن أن fake يطابق العقد نفسه الذي يستخدمه الكود الحقيقي.

لا تبنِ mock ضخماً إذا كان fake صغير يكفي. fake هو تنفيذ بسيط predictable. مثلاً UserStore يرجع مستخدماً ثابتاً. هذا أسهل من محاكاة مكتبة كاملة.

مثال عملي

index.ts

الدالة لا تعرف هل store حقيقي أو fake. تعرف فقط العقد.

ماذا يحدث عندما ينحرف العقد؟

هذا هو الضمان الحقيقي: عندما يتغيّر الـ interface وينسى أحدهم تحديث الـ fake، الاختبار لا يفشل وقت التشغيل — بل يرفض الكود الترجمة أصلاً. أضف طريقة جديدة إلى UserStore:

interface UserStore {
  findName(id: number): string | undefined;
  findEmail(id: number): string | undefined; // ← العقد تغيّر
}

// الـ fake القديم لم يعد يطابق العقد:
const fakeStore: UserStore = {
  findName: () => "Sara",
};
// error TS2741: Property 'findEmail' is missing in type
// '{ findName: () => string; }' but required in type 'UserStore'.

في لغة بلا أنواع، هذا الـ fake الناقص يمرّ بصمت ويعطيك اختباراً أخضر لعقد لم يعد موجوداً. في TypeScript، انحراف العقد يظهر كخطأ ترجمة في كل fake وكل mock دفعة واحدة — قبل تشغيل أي اختبار. هذا ما تعنيه عبارة «TypeScript يضمن أن fake يطابق العقد».

أدوات الاختبار — Test Runners

Vitest هو runner الاختبار الكانوني في 2026 لمشاريع TypeScript. سريع، يدعم ESM، ويعمل مباشرة مع TypeScript بدون إعداد:

npm install -D vitest

اكتب ملفات *.test.ts وشغّلها:

npx vitest

مثال اختبار كامل مع mock:

index.ts

node:test (Node.js ≥ 20 builtin) هو البديل بدون dependencies:

import { describe, it } from "node:test";
import assert from "node:assert/strict";

describe("upper", () => {
  it("uppercases", () => assert.equal(upper("hi"), "HI"));
});

استخدم node:test عندما تريد صفر dependencies. استخدم Vitest في مشاريع كبيرة تستفيد من watch mode والتقارير المتقدمة.

التصميم للاختبار

مرر التبعيات بدلاً من إنشائها داخل الدالة عندما يكون ذلك مناسباً. هذا يقلل coupling.

تحدي — Challenge