Unit Test مقابل Integration Test
أساس استراتيجية الاختبار في iOS: هل الاختبارات الوحدوية (unit tests) التي تعزل كل جزء على حدة، أم اختبارات التكامل (integration tests) التي تتحقق من تفاعل المكونات؟ كيف تبني هرم الاختبار الصحيح؟
مُشغّل اختبارات native لـ ESM/TS بسرعة Vite نفسها
ناضج منذ 13 عامًا، وهو الخيار الافتراضي في React Native
في مشروع جديد مبني على Vite أو Nuxt، يجب أن يكون Vitest هو الخيار الافتراضي: فأنت تشارك نفس ملف vite.config.js. في Next.js يبقى الإعداد منفصلاً (مترجمه ليس Vite)، لكنك تحصل على دعم native لـ ESM/TypeScript دون تثبيت حزمة تحويل إضافية.
لكن إذا كانت لديك مجموعة اختبارات Jest كبيرة وتعمل بشكل جيد، خصوصًا إذا كنت تعتمد على React Native/Metro، فقد تتجاوز تكلفة الترحيل فائدته. اختر الطريق الثالث: اكتب الاختبارات الجديدة بـ Vitest، واترك المجموعة الحالية في Jest — يمكن للاثنين التعايش في نفس المونوريبو.
| الفئة | Vitest 5 | Jest |
|---|---|---|
| الأداء | 9/10 | 7/10 |
| سهولة التعلّم | 7/10 | 7/10 |
| النظام البيئي | 6/10 | 9/10 |
| المجتمع | 6/10 | 9/10 |
| سوق العمل | 6/10 | 8/10 |
| الاستدامة المستقبلية | 9/10 | 6/10 |
// Vitest 5 - اختبار الدالة التي تحسب إجمالي السلة
// vitest.config.ts يشارك vite.config.ts؛ لا حاجة لطبقة تحويل إضافية
import { describe, it, expect, vi } from 'vitest'
import { calculateCartTotal } from './cart'
import { fetchDiscount } from './discount-api'
vi.mock('./discount-api')
describe('calculateCartTotal', () => {
// Vitest 5: clearMocks افتراضيًا true، لا حاجة لاستدعاء تنظيف إضافي
it('calculates the subtotal correctly without a discount code', () => {
const items = [
{ price: 129.9, qty: 2 },
{ price: 49.5, qty: 1 },
]
expect(calculateCartTotal(items)).toBeCloseTo(309.3, 2)
})
it('uses a conditional mock with vi.when for a valid discount code', async () => {
// Vitest 5 API جديد: سلوك mock مختلف حسب الوسيطة (argument)
vi.when(fetchDiscount).calledWith('CART10').thenResolve({ percent: 10 })
vi.when(fetchDiscount).calledWith('INVALID').thenReject(new Error('invalid code'))
const items = [{ price: 100, qty: 1 }]
const total = await calculateCartTotal(items, 'CART10')
expect(total).toBeCloseTo(90, 2)
expect(fetchDiscount).toHaveBeenCalledWith('CART10')
})
it('throws an error for an invalid code', async () => {
vi.when(fetchDiscount).calledWith('INVALID').thenReject(new Error('invalid code'))
const items = [{ price: 100, qty: 1 }]
await expect(calculateCartTotal(items, 'INVALID')).rejects.toThrow('invalid code')
})
})
// Monorepo: vitest -p web --coverage (فقط مشروع 'web' + تقرير التغطية)// Jest 30 - اختبار الدالة التي تحسب إجمالي السلة
// يجب أن تكون سلسلة تحويل babel.config.js أو ts-jest مُعدة مسبقًا
const { calculateCartTotal } = require('./cart')
const { fetchDiscount } = require('./discount-api')
jest.mock('./discount-api')
describe('calculateCartTotal', () => {
afterEach(() => {
jest.clearAllMocks() // ليست افتراضية في Jest، تُستدعى يدويًا
})
it('calculates the subtotal correctly without a discount code', () => {
const items = [
{ price: 129.9, qty: 2 },
{ price: 49.5, qty: 1 },
]
expect(calculateCartTotal(items)).toBeCloseTo(309.3, 2)
})
it('uses mockResolvedValue for a valid discount code', async () => {
fetchDiscount.mockImplementation((code) => {
if (code === 'CART10') return Promise.resolve({ percent: 10 })
return Promise.reject(new Error('invalid code'))
})
const items = [{ price: 100, qty: 1 }]
const total = await calculateCartTotal(items, 'CART10')
expect(total).toBeCloseTo(90, 2)
expect(fetchDiscount).toHaveBeenCalledWith('CART10')
})
it('throws an error for an invalid code', async () => {
fetchDiscount.mockRejectedValue(new Error('invalid code'))
const items = [{ price: 100, qty: 1 }]
await expect(calculateCartTotal(items, 'INVALID')).rejects.toThrow('invalid code')
})
})
// شغّل حزمة 'web' فقط في المونوريبو باستخدام jest --projects packages/web --coverageفي مشروع جديد مبني على Vite أو Nuxt، يجب أن يكون Vitest هو الخيار الافتراضي: فأنت تشارك نفس ملف vite.config.js. في Next.js يبقى الإعداد منفصلاً (مترجمه ليس Vite)، لكنك تحصل على دعم native لـ ESM/TypeScript دون تثبيت حزمة تحويل إضافية.
لكن إذا كانت لديك مجموعة اختبارات Jest كبيرة وتعمل بشكل جيد، خصوصًا إذا كنت تعتمد على React Native/Metro، فقد تتجاوز تكلفة الترحيل فائدته. اختر الطريق الثالث: اكتب الاختبارات الجديدة بـ Vitest، واترك المجموعة الحالية في Jest — يمكن للاثنين التعايش في نفس المونوريبو.
لا، لا يحل محله تمامًا. كلاهما قيد التطوير النشط في سبتمبر 2026: Vitest 5.0 (3 سبتمبر 2026) وJest 30.5.2 (18 سبتمبر 2026). في المشاريع المبنية على Vite وNuxt، يكون عبء الإعداد أقل في Vitest لأنه يعيد استخدام خط تحويل التطبيق نفسه؛ بينما يستمر Jest خصوصًا في React Native/Metro وقواعد الأكواد الكبيرة القائمة.