اختبار TypeScript: الوحدة، التكامل، E2E — دليل شامل

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

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

ابدأ الدورة

مقدمة: لماذا نحتاج إلى اختبار كود TypeScript؟

TypeScript هي أداة قوية تضيف الكتابة الثابتة (static typing) إلى JavaScript، مما يسمح باكتشاف الأخطاء في مرحلة الترجمة. ومع ذلك، حتى أكثر أنظمة الأنواع صرامة لا تضمن أن الكود الخاص بك سيعمل بشكل صحيح في الظروف الحقيقية. الأخطاء المنطقية، والمعالجة غير الصحيحة للحالات الحدودية، ومشاكل تكامل الوحدات تبقى خارج نطاق المترجم. وهنا يأتي دور الاختبار.

الاختبار في TypeScript ليس مجرد التحقق من الدوال. إنها عملية شاملة تتضمن ثلاثة مستويات رئيسية: Unit (اختبار الوحدات)، Integration (اختبار التكامل)، و E2E (الاختبار الشامل). كل منها يحل مشكلة محددة، ومعًا يشكلون "هرم الاختبار" الذي يضمن موثوقية التطبيق.

في هذه المقالة، سنشرح كيفية كتابة اختبارات لـ TypeScript على جميع المستويات الثلاثة باستخدام أدوات حديثة: Jest و Supertest و Playwright. ستتعرف على الأخطاء التي تساعد هذه الاختبارات في منعها وكيفية دمجها في مشروعك.



اختبار الوحدات (Unit Testing): التحقق من الوحدات المعزولة

اختبارات الوحدات (Unit tests) هي أساس الهرم. إنها تختبر دوالًا أو كلاسات أو طرقًا منفردة بمعزل عن التبعيات الخارجية (قواعد البيانات، واجهات API، نظام الملفات). الهدف الرئيسي هو التأكد من أن كل "لبنة" في تطبيقك تعمل بشكل صحيح.



الأدوات والإعداد

الإطار الأكثر شيوعًا لاختبار الوحدات في TypeScript هو Jest. يوفر دعمًا مدمجًا لـ TypeScript من خلال ts-jest أو @swc/jest.

تثبيت Jest في المشروع:

npm install --save-dev jest @types/jest ts-jestnpx ts-jest config:init


مثال على اختبار وحدة

لنفكر في دالة بسيطة لحساب الخصم:

// discount.tsexport function applyDiscount(price: number, discountPercent: number): number {  if (discountPercent < 0 || discountPercent > 100) {    throw new Error('نسبة الخصم يجب أن تكون بين 0 و 100');  }  return price - (price * discountPercent) / 100;}

سنكتب اختبارات وحدة تغطي السيناريوهات الرئيسية:

// discount.test.tsimport { applyDiscount } from './discount';

describe('applyDiscount', () => { it('يجب أن يطبق خصم 20% بشكل صحيح', () => { expect(applyDiscount(100, 20)).toBe(80); });

it('يجب أن يعيد السعر الأصلي عند خصم 0%', () => { expect(applyDiscount(50, 0)).toBe(50); });

it('يجب أن يعيد 0 عند خصم 100%', () => { expect(applyDiscount(200, 100)).toBe(0); });

it('يجب أن يرمي خطأ عند خصم سالب', () => { expect(() => applyDiscount(100, -10)).toThrow('نسبة الخصم يجب أن تكون بين 0 و 100'); });

it('يجب أن يرمي خطأ عند خصم أكبر من 100%', () => { expect(() => applyDiscount(100, 150)).toThrow('نسبة الخصم يجب أن تكون بين 0 و 100'); });});

مهم: يجب ألا تصل اختبارات الوحدات إلى الموارد الخارجية. بدلاً من ذلك، استخدم الكائنات الوهمية (mocks) لاستبدال التبعيات، على سبيل المثال، باستخدام jest.mock().



اختبار التكامل (Integration Testing): التفاعل بين الوحدات

تتحقق اختبارات التكامل من كيفية عمل الأجزاء المختلفة من النظام معًا. يمكن أن يكون هذا التفاعل بين خدمة وقاعدة بيانات، أو بين وحدة تحكم ومستودع، أو بين الخدمات المصغرة. على عكس اختبارات الوحدات، نحن هنا لا نعزل المكونات تمامًا.



مثال: اختبار REST API

لنفترض أن لدينا تطبيق Express مع نقطة نهاية واحدة. لاختبار طلبات HTTP، نستخدم Supertest.

// userController.tsimport { Router, Request, Response } from 'express';

interface User { id: number; name: string;}

const users: User[] = [{ id: 1, name: 'Alice' }];

المدونات

توصيات الكتب