الثغرات في مجموعة اختباراتك التي تسمح للأخطاء بالهروب
المسار السعيد مختبر، لكن ماذا عن القيم الفارغة والمصفوفات الفارغة والشروط الحدية؟
الاختبارات التي تنجح أحياناً وتفشل أحياناً أخرى — القتلة الصامتون لثقة CI/CD
الاختبارات التي تعتمد على بعضها البعض أو تشترك في حالة قابلة للتغيير — كوابيس التصحيح
من اختبارات الوحدة إلى E2E، محلل الاختبارات يراجعها جميعاً
اختبار على مستوى الدوال والفئات
اختبار تفاعل المكونات
اختبار تدفق المستخدم من البداية إلى النهاية
اختبار نقاط النهاية والعقود
اكتشاف تراجع واجهة المستخدم
اختبار التحميل والأداء المعياري
أمثلة حقيقية على تحسينات الاختبارات
describe('calculateDiscount', () => {
it('applies 10% for orders over $100', () => {
expect(calculateDiscount(150)).toBe(15)
})
it('applies 5% for orders over $50', () => {
expect(calculateDiscount(75)).toBe(3.75)
})
// What about $0? Negative? Exactly $50? $100?
})اختبارات الحدود مفقودة: $0، $50، $100، سالب
describe('calculateDiscount', () => {
it('applies 10% for orders over $100', () => {
expect(calculateDiscount(150)).toBe(15)
})
it('applies 5% for orders over $50', () => {
expect(calculateDiscount(75)).toBe(3.75)
})
it('returns 0 for orders at boundary', () => {
expect(calculateDiscount(50)).toBe(0)
expect(calculateDiscount(100)).toBe(5) // 5% tier
})
it('handles zero and negative gracefully', () => {
expect(calculateDiscount(0)).toBe(0)
expect(calculateDiscount(-10)).toBe(0)
})
})إضافة حالات حدية للحدود والمدخلات غير الصالحة
it('shows notification after save', async () => {
await user.click(saveButton)
// Flaky! Depends on timing
await waitFor(() => {
expect(screen.getByText('Saved!')).toBeVisible()
})
// Even worse: arbitrary timeout
await new Promise(r => setTimeout(r, 100))
expect(notificationCount).toBe(1)
})مهلات عشوائية وافتراضات توقيت
it('shows notification after save', async () => {
await user.click(saveButton)
// Wait for specific state change
await waitFor(() => {
expect(screen.getByRole('alert')).toHaveTextContent('Saved!')
})
// Assert on observable behavior, not timing
expect(
await screen.findByRole('alert', { name: /saved/i })
).toBeVisible()
})انتظر تغييرات الحالة الملاحظة، وليس الوقت
let testUser: User
beforeAll(async () => {
// Shared across ALL tests — mutations leak!
testUser = await createUser({ name: 'Test' })
})
it('updates user name', async () => {
await updateUser(testUser.id, { name: 'Updated' })
// Now testUser.name is 'Updated' for all following tests
})
it('checks original name', () => {
// FAILS! Previous test mutated shared state
expect(testUser.name).toBe('Test')
})الحالة المشتركة في beforeAll تتسرب بين الاختبارات
describe('user updates', () => {
let testUser: User
beforeEach(async () => {
// Fresh user for EACH test
testUser = await createUser({ name: 'Test' })
})
afterEach(async () => {
await deleteUser(testUser.id)
})
it('updates user name', async () => {
await updateUser(testUser.id, { name: 'Updated' })
expect(testUser.name).toBe('Updated')
})
it('checks original name', () => {
// Works! Fresh testUser with original name
expect(testUser.name).toBe('Test')
})
})استخدم beforeEach لعزل الاختبارات
محلل الاختبارات لا يكتفي بعدّ الاختبارات — بل يحلل ما تختبره فعلاً. يجد الفجوات بين ما تغطيه اختباراتك وما يحتاجه كودك.
يرسم خريطة مسارات الكود للعثور على الفروع غير المختبرة
يحدد اعتماديات التوقيت والترتيب
يوصي بحالات اختبار محددة للإضافة
تحليل تغطية الاختبارات
يرسم خريطة مسارات الكود المختبرة وغير المختبرة
تحديد نقاط الضعف
يجد الحالات الحدية وحالات الأخطاء بدون اختبارات
اكتشاف الأنماط السيئة
يكتشف الأنماط غير المستقرة ومشاكل العزل
اقتراح التحسينات
يوصي بحالات اختبار محددة للإضافة
الاختبارات السيئة أسوأ من عدم وجود اختبارات — فهي تعطي ثقة زائفة
الاختبارات التي تغطي الحالات الحدية تكتشف الأخطاء قبل المستخدمين
لا مزيد من "إعادة المحاولة حتى النجاح" — الاختبارات تنجح أو تفشل لأسباب حقيقية
الاختبارات الجيدة تتيح لك تغيير الكود بثقة
تغطية 100% لا تعني شيئاً إذا لم تكتشف الاختبارات الأخطاء.
محلل الاختبارات يضمن أن اختباراتك تعمل فعلاً.
دع محلل الاختبارات يجد الثغرات في مجموعة اختباراتك. مجاني لمدة 14 يوماً، لا حاجة لبطاقة ائتمان.