Когда целесообразно использовать end to end тесты с учетом их влияния на скорость CI?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
End-to-End тесты: когда они целесообразны
Проблема: скорость CI
E2E тесты значительно медленнее unit и интеграционных тестов. Они запускают полный браузер, загружают все ресурсы, выполняют реальное взаимодействие. Типичный E2E тест занимает 5-30 секунд, в то время как unit тест выполняется за миллисекунды.
// Unit тест - быстро (1-50 мс)
test('formatDate возвращает правильную строку', () => {
expect(formatDate(new Date('2024-01-15'))).toBe('15.01.2024')
})
// E2E тест - медленно (5000+ мс)
test('пользователь может заполнить форму и отправить', async ({ page }) => {
await page.goto('/register')
await page.fill('input[name="email"]', 'test@example.com')
await page.fill('input[name="password"]', 'password123')
await page.click('button[type="submit"]')
await page.waitForNavigation()
expect(page.url()).toContain('/success')
})
Пирамида тестирования
Правильный баланс тестов выглядит как пирамида:
- 70-80% Unit тесты (быстрые, дешевые)
- 10-20% Интеграционные тесты (средней скорости)
- 5-10% E2E тесты (медленные, дорогие)
Это минимизирует время CI при максимальном покрытии.
Когда E2E тесты ЦЕЛЕСООБРАЗНЫ
1. Критические пути пользователя
Тестируй самые важные сценарии, которые приносят деньги:
// Регистрация и оплата - критично
test('пользователь может зарегистрироваться и оплатить подписку', async () => {
// ...
})
// Форматирование даты в деталях профиля - менее критично
2. Интеграция с бэкендом
Если нужно проверить, что фронт и бэк работают вместе:
// Интеграция нужна
test('при загрузке страницы профиля данные загружаются с API', async ({ page }) => {
await page.goto('/profile')
await page.waitForSelector('[data-testid="profile-name"]')
expect(await page.textContent('[data-testid="profile-name"]')).toBe('John')
})
3. Взаимодействия, которые сложно протестировать unit'ами
- Модальные окна и드롭다운
- Мультишаговые формы
- Анимации и переходы
- Управление фокусом
test('модальное окно открывается и закрывается', async ({ page }) => {
await page.click('button[aria-label="Open modal"]')
await page.waitForSelector('.modal')
expect(await page.isVisible('.modal')).toBe(true)
await page.click('button.close')
await page.waitForSelector('.modal', { state: 'hidden' })
})
Когда E2E тесты ИЗБЫТОЧНЫ
1. Бизнес-логика компонента
// Плохо - использовать E2E
test('цена вычисляется корректно', async ({ page }) => {
await page.fill('input[name="quantity"]', '5')
expect(await page.textContent('.total')).toBe('$500')
})
// Хорошо - unit тест
test('calculateTotal(100, 5) = 500', () => {
expect(calculateTotal(100, 5)).toBe(500)
})
2. Ошибки валидации форм
// Избыточный E2E
test('показывается ошибка при пустом email', async ({ page }) => {
await page.click('button[type="submit"]')
expect(await page.textContent('.error')).toContain('Email required')
})
// Достаточно unit теста на валидацию
test('validator.email() возвращает error при пусто', () => {
expect(validator.email('')).toContain('required')
})
Оптимизация E2E тестов для скорости CI
1. Параллельное выполнение
// playwright.config.ts
export default defineConfig({
fullyParallel: true,
workers: process.env.CI ? 4 : undefined,
timeout: 30000,
})
2. Ограничь количество E2E тестов
// Вместо 100 E2E тестов - 20 критических
// + 500 unit тестов
// = полное покрытие + быстрый CI
3. Используй seeding вместо UI для подготовки данных
// Медленно
test('пользователь видит свои заказы', async ({ page }) => {
await registerUser(page)
await createOrder(page)
await page.goto('/orders')
// ...
})
// Быстро
test('пользователь видит свои заказы', async ({ page, request }) => {
const user = await request.post('/api/v1/users', { data: userData })
const order = await request.post('/api/v1/orders', { data: orderData })
await page.goto('/orders')
// ...
})
Вывод
E2E тесты целесообразны для:
- Критических пользовательских потоков
- Сложных интеграций между компонентами
- Проверки работы с реальным API
Но их должно быть 5-10% от всех тестов. Остальное - unit тесты, которые запускаются в миллисекунды и дают быстрый feedback в CI.