الاختبار المتقدم في TypeScript: من الوحدة إلى E2E
الاختبار ليس مجرد التحقق من صلاحية الكود، بل هو أساس التطوير الاحترافي في TypeScript. على المستوى المتقدم، ننتقل من التأكيدات البسيطة إلى بناء أهرامات اختبارية معزولة وسريعة وموثوقة. في هذه المقالة، سنحلل الأساليب العملية لاختبار الوحدة والتكامل وE2E باستخدام أفضل أدوات نظام TypeScript البيئي.
1. اختبار الوحدة المتقدم مع Jest و TypeScript
تتحقق اختبارات الوحدة من الوحدات المعزولة. في TypeScript، التحدي الرئيسي هو التعامل مع التبعيات والأنواع وعدم التزامن.
1.1. الكائنات الوهمية والكتابة مع jest.mocked
استخدم jest.mocked للكتابة الكاملة للكائنات الوهمية. هذا يضمن عدم استدعاء طريقة غير موجودة.
import { fetchUserData } from './api';import { processUser } from './userProcessor';
jest.mock('./api');
const mockedFetchUserData = jest.mocked(fetchUserData);
describe('processUser', () => { it('يجب معالجة بيانات المستخدم', async () => { const mockUser = { id: 1, name: 'Alice', email: 'alice@test.com' }; mockedFetchUserData.mockResolvedValue(mockUser);
const result = await processUser(1);
expect(result).toEqual({ displayName: 'Alice', contact: 'alice@test.com' }); expect(mockedFetchUserData).toHaveBeenCalledWith(1); });
it('يجب رمي خطأ عند عدم وجود البريد الإلكتروني', async () => { mockedFetchUserData.mockResolvedValue({ id: 2, name: 'Bob', email: null }); await expect(processUser(2)).rejects.toThrow('Email is required'); });});1.2. اختبار الأنواع المعقدة والأجناس العامة
للدوال ذات الأجناس العامة، قم بإنشاء أنواع مساعدة للاختبار لتجنب التكرار.
// الكودfunction getFirstElement<T>(arr: T[]): T | undefined { return arr[0];}
// الاختبارtype TestArray = number[];const array: TestArray = [10, 20, 30];
describe('getFirstElement', () => { it('يجب إرجاع العنصر الأول من الأرقام', () => { const result = getFirstElement(array); expect(result).toBe(10); // TypeScript يستنتج تلقائياً النوع number });
it('يجب إرجاع undefined لمصفوفة فارغة', () => { const result = getFirstElement([]); expect(result).toBeUndefined(); });});2. اختبار التكامل: قاعدة البيانات و API
تتحقق اختبارات التكامل من تفاعل الوحدات: المتحكمات والخدمات وقاعدة البيانات. لتطبيقات TypeScript على Node.js، فإن المجموعة المثالية هي Jest + Supertest + Testcontainers.
2.1. إعداد قاعدة بيانات اختبارية مع Testcontainers
يقوم Testcontainers بتشغيل PostgreSQL في Docker، مما يضمن بيئة نظيفة لكل اختبار.
import { PostgreSqlContainer, StartedPostgreSqlContainer } from '@testcontainers/postgresql';import { Client } from 'pg';
let container: StartedPostgreSqlContainer;let client: Client;
beforeAll(async () => { container = await new PostgreSqlContainer().start(); client = new Client({ connectionString: container.getConnectionUri() }); await client.connect(); await client.query(` CREATE TABLE users ( id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(100) UNIQUE NOT NULL ); `);}, 30000); // مهلة 30 ثانية لتحميل الصورة
afterAll(async () => { await client.end(); await container.stop();});
describe('مستودع المستخدم', () => { it('يجب إنشاء وإرجاع مستخدم', async () => { const res = await client.query( `INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *`, ['Test', 'test@example.com'] ); expect(res.rows[0].name).toBe('Test'); });});2.2. اختبار REST API مع Supertest
تشغيل تطبيق Express واختبا