В TDD-команде разработчики пишут тесты до кода, что поднимает практический вопрос: что остаётся QA? Юнит-тесты не заменяют интеграционные тесты, E2E-верификацию или edge case которые разработчики не догадались специфицировать. Статья разбирает как QA вписывается в TDD-рабочие процессы, что такое acceptance test-driven development (ATDD) на практике, и почему TDD требует сдвига QA-работы раньше, а не её устранения.
Что такое TDD на самом деле
TDD-цикл состоит из трёх шагов. Red: написать падающий тест для нужного поведения. Green: написать минимальный код чтобы тест прошёл. Refactor: почистить код без нарушения теста. Повторить для следующего поведения.
Ключевое слово: "минимальный". Пишется ровно столько кода чтобы тест прошёл, и ни строчки больше. Это заставляет реализацию следовать из спецификации (теста), а не наоборот.
Что TDD меняет в коде
TDD производит код который:
Тестируемый по дизайну. Код который сложно тестировать часто сигнализирует о плохом дизайне: тесная связность, скрытые зависимости, слишком много ответственностей. TDD принуждает к тестируемости в момент написания, а не как запоздалую мысль. Покрытый по определению. У каждого поведения есть тест, потому что нужно было написать тест чтобы написать поведение. Инкрементальный. Фичи строятся небольшими верифицированными шагами. Нет "написать всё, потом тестировать". Задокументированный. Тест-сьют: исполняемая спецификация. Чтение тестов говорит что должен делать код.Место QA-инженеров в TDD-командах
QA-инженеры в TDD-командах сталкиваются с парадоксом: разработчики уже пишут тесты. Что остаётся?
Несколько вещей.
Тестирование более высокого уровня. Разработчики пишут юнит-тесты. QA-инженеры пишут интеграционные и E2E-тесты. TDD на уровне юнит-тестов не заменяет E2E-верификацию. Acceptance test-driven development (ATDD). QA-инженеры пишут acceptance-тесты до того как разработчики пишут любой код. Разработчики делают эти тесты проходящими. Это TDD на уровне фичи. Требует участия QA с начала разработки, а не с конца. Исследовательское тестирование и edge case. TDD-тесты пишут разработчики которые знают как работает система. QA-инженеры тестируют то что разработчики не догадались специфицировать: edge case, необычные входные данные, точки интеграции, производительность под нагрузкой. Ревью качества тестов. Разработческие тесты реально тестируют правильные вещи? Они тестируют поведение или реализацию? Поймают ли они важные баги? QA-инженеры могут ревьюить тест-код, а не только продукт-код.Acceptance test-driven development (ATDD)
ATDD: QA-релевантная версия TDD. Рабочий процесс:
1. Бизнес-стейкхолдер описывает фичу в пользовательских терминах
2. QA-инженер переводит это в acceptance criteria и acceptance-тесты
3. Разработчики реализуют до тех пор пока acceptance-тесты не проходят
4. QA верифицирует и тесты и реализацию
Acceptance-тесты становятся источником истины о том что означает "готово". Фича готова когда её acceptance-тесты проходят.
В терминах Playwright:
// Написан до того как реализация существует
test('user can reset password via email', async ({ page }) => {
// Дано: пользователь с зарегистрированным email
const userEmail = 'testuser@example.com';
// Когда: запрашивает сброс пароля
await page.goto('/forgot-password');
await page.getByLabel('Email address').fill(userEmail);
await page.getByRole('button', { name: 'Send reset link' }).click();
// Тогда: видит сообщение подтверждения
await expect(page.getByRole('alert')).toHaveText(
'If that email is registered, a reset link is on its way.'
);
// И: получает письмо сброса (верифицируется через test email API)
const inbox = await testEmailAPI.getInbox(userEmail);
expect(inbox.some(m => m.subject.includes('Reset your password'))).toBe(true);
});Этот тест написан до того как фича построена. Задача разработчика: сделать его проходящим.
Behaviour-Driven Development (BDD)
BDD: эволюция ATDD которая добавляет общий язык (обычно Gherkin) для написания тестов которые могут читать не-инженеры:
Feature: Password reset
Scenario: User resets password via email
Given a user with email "testuser@example.com" is registered
When they submit the forgot password form with that email
Then they see "If that email is registered, a reset link is on its way."
And they receive a password reset email within 1 minuteЭти Gherkin-сценарии маппятся на Playwright-тест-код через слой определений шагов (с использованием инструментов вроде Cucumber.js или BDD-плагинов Playwright).
BDD наиболее ценен когда нетехнические стейкхолдеры пишут или ревьюят сценарии. Он добавляет накладные расходы для команд где все стейкхолдеры могут читать код.
Должны ли QA-инженеры практиковать TDD сами?
Для кода тест-автоматизации: в основном нет. TDD предназначен для продакшн-кода где проектируется система. Тест-код должен быть простым в написании и верификации. Написание тестов для тест-кода создаёт излишнюю сложность.
Исключение: QA-инженеры которые строят тест-фреймворки или утилиты (хелперы page object, утилиты фикстур, интеграции с отчётностью) могут выиграть от TDD при создании этих инструментов.
Практический вывод для QA в TDD-командах
1. Включайся до написания кода. Ревьюй user stories на тестируемость. Пиши acceptance criteria. Определяй edge case.
2. Пиши acceptance-тесты рано. Даже если разработчики не практикуют формальный ATDD, написание acceptance-тестов до начала разработки формирует реализацию.
3. Сдвигай исследовательское тестирование раньше. В TDD-командах исследовательское тестирование важнее, потому что именно оно находит то что тесты не специфицировали.
4. Ревьюй разработческие тесты. Не по числам покрытия, а по тому действительно ли тесты верифицируют поведение которое имеет значение.
TDD не устраняет потребность в QA-инженерах. Он меняет где происходит QA-работа: не после кода, а вместе с ним.
→ See also: Test-Driven Development для QA: написание тестов до кода | Shift-left тестирование: что это значит и как практиковать | Практики автоматизации тестирования, которые реально важны