Ручное тестирование: исследовательское, смоук, регресс, приёмочное
Есть удобный миф: ручное тестирование — временная стадия, которую индустрия проходит по пути к полной автоматизации. Миф удобен всем. Менеджеру он обещает, что затраты на QA когда-нибудь станут нулевыми. Разработчику — что «ручники» просто не умеют писать код. Самому тестировщику — повод тревожиться и переучиваться на автоматизатора.
Проблема мифа в том, что он путает две разные вещи: повторение известных проверок и поиск неизвестного. Первое действительно нужно автоматизировать — компьютер повторяет лучше человека, дешевле и без скуки. Второе автоматизировать невозможно в принципе, потому что автоматизировать можно только то, что вы уже придумали. Скрипт проверяет ответ на вопрос, который вы задали позавчера. Человек задаёт новый вопрос прямо сейчас, глядя на экран.
Эта статья — про вторую часть работы и про четыре её основные формы. Мы уже разобрали, как выбирать проверки (https://courses.digitable.life/post/testing/02-test-design/) и как их оформлять (https://courses.digitable.life/post/testing/03-documentation/). Здесь — как эти проверки реально выполняются руками, в каком режиме, с каким бюджетом времени и по каким критериям останавливаться.
1. Проблема оракула: почему человека нельзя выкинуть
В теории тестирования оракул — это способ узнать, правильно ли повёл себя продукт. Автотест содержит
оракул внутри себя в виде assert: ожидаемое значение зафиксировано заранее. И это его фундаментальное
ограничение — автотест умеет проверить только то свойство, которое кто-то догадался записать.
Посмотрим на конкретный экран. Автотест проверяет:
await expect(page.getByTestId('order-total')).toHaveText('12 480 ₽');
Тест зелёный. Тем временем на экране:
- сумма отображается корректно, но кнопка «Оплатить» уехала за пределы вьюпорта на 13-дюймовом ноутбуке;
- рядом висит прошлогодний баннер «Скидка до 31 декабря»;
- в позиции товара написано «1 шт.» при количестве 3 — в сумме учтено верно, в строке нет;
- страница отрисовалась за 9 секунд, и все 9 секунд был белый экран без индикатора;
- в письме подтверждения имя клиента — «undefined».
Ни одна из этих проблем не «падает» ни в одном автотесте, потому что ни одна из них не была заранее сформулирована как утверждение. Человек замечает их за десять секунд — не потому что он внимательнее машины, а потому что у него принципиально другой оракул: набор нечётких ожиданий о том, каким продукт должен быть.
Джеймс Бах и Майкл Болтон свели эти ожидания в мнемонику HICCUPPS(F) — список источников, по которым человек判 судит о неправильности (The Oracle Problem and the Teaching of Software Testing):
| Буква | Источник ожидания | Вопрос, который вы задаёте |
|---|---|---|
| H | History | Раньше работало иначе. Это осознанное изменение? |
| I | Image | Так может выглядеть продукт компании с такой репутацией? |
| C | Comparable products | У конкурента/соседнего модуля это сделано иначе. Почему? |
| C | Claims | Мы сами обещали это в доке, релиз-ноутах, рекламе |
| U | User expectations | Разумный пользователь ожидал бы другого |
| P | Product | Внутри самого продукта два места ведут себя противоречиво |
| P | Purpose | Формально по спеке верно, но задачу пользователя не решает |
| S | Standards | Нарушены стандарты, законы, гайдлайны платформы, WCAG |
| F | Familiarity | Похоже на класс дефектов, который у нас уже случался |
Практический приём: когда «что-то не так, но по спеке всё верно» — прогоните ощущение по этому списку.
Он превращает «мне не нравится» в формулировку, которую можно защитить перед разработчиком и продактом.
Баг-репорт «неудобно» закроют как won't fix; баг-репорт «противоречит нашему же тексту в справке (Claims)
и гайдлайну iOS (Standards)» — почините.
Разработчику. Это и есть ответ на вопрос «зачем нам тестировщик, если у меня зелёный CI». Ваш CI проверяет соответствие коду ваших же ожиданий. Тестировщик проверяет соответствие ожиданиям, которых у вас не было. Это не дублирование — это другой источник информации.
2. Карта видов: что чем занимается
тестирование)) По цели Смоук билд пригоден? 10-15 минут блокирует всё Регресс старое не сломалось? растёт с релизами кандидат на автоматизацию Исследовательское чего мы не знаем? чартер + сессия находит незапланированное Приёмочное берём или нет? решает заказчик критерии заранее По знанию системы Чёрный ящик Серый ящик логи и DevTools Белый ящик По формализации Сценарное шаг за шагом Чек-лист Свободный поиск ad-hoc
Ключевое различие, которое стоит держать в голове: смоук и регресс отвечают на закрытые вопросы («работает ли то, что мы уже описали?»), исследовательское — на открытый («что здесь вообще происходит?»), приёмочное — на вопрос о деньгах («мы это принимаем?»). Разные вопросы требуют разного режима работы, разной документации и разных метрик успеха. Смешивать их — самая частая организационная ошибка: команда «делает регресс», в котором человек попутно исследует, отвлекается, не проходит половину чек-листа и не может внятно отчитаться ни по одному фронту.
3. Смоук-тестирование: контракт «билд пригоден для работы»
Название пришло из электроники: собрал плату, подал питание, если дым не пошёл — можно продолжать проверки. Смысл тот же — смоук не ищет баги, он защищает время команды. Если билд разваливается на логине, нет смысла тратить восемь человеко-часов на регресс.
Три свойства правильного смоука:
- Короткий. 10–15 минут максимум, иначе он не будет выполняться каждый раз.
- Широкий и мелкий. По одному самому простому happy-path сценарию на каждую критичную подсистему. Никаких граничных значений — они в регрессе.
- Бинарный и блокирующий. Результат — «билд принят» / «билд отклонён». Есть фейл — билд возвращается разработчику, дальнейшее тестирование не начинается. Смоук без права заблокировать — ритуал, а не гейт.
Пример чек-листа для e-commerce, который влезает в 12 минут:
## Смоук: релиз-кандидат RC-2.14, окружение staging
Предусловия: свежий деплой, миграции применены, версия в /health совпадает с ожидаемой.
- [ ] `/health` отвечает 200, поле `version` = RC-2.14, `db: ok`, `redis: ok`
- [ ] Главная страница открывается, есть товары, нет 5xx в консоли браузера
- [ ] Логин существующим пользователем (smoke_user@example.com) — успешен
- [ ] Поиск по слову «кофе» возвращает непустой результат
- [ ] Карточка товара открывается, цена и наличие отображаются
- [ ] Товар добавляется в корзину, счётчик обновился
- [ ] Оформление заказа доходит до страницы оплаты (тестовая карта 4111...)
- [ ] Заказ появился в личном кабинете и в админке
- [ ] Письмо-подтверждение пришло в mailhog
- [ ] Логи приложения без ERROR за время прохождения
Вердикт: ПРИНЯТ / ОТКЛОНЁН (причина, ссылка на баг)
Время: ____ мин. Исполнитель: ____
Обратите внимание: в чек-листе нет шагов «нажмите кнопку X». Это осознанно — чек-лист пишется для того, кто знает продукт, и проверяет результаты, а не диктует действия. Разница между чек-листом и тест-кейсом разобрана в https://courses.digitable.life/post/testing/03-documentation/; для смоука почти всегда правильный формат — именно чек-лист.
Смоук против санити
Термины путают постоянно, и в разных компаниях они означают разное. Рабочее разделение:
| Смоук | Санити (sanity) | |
|---|---|---|
| Когда | На каждый билд/деплой | После точечного фикса или мелкого изменения |
| Охват | Широкий, все критичные подсистемы | Узкий, только затронутая область + соседи |
| Глубина | Минимальная | Достаточная, чтобы поверить в фикс |
| Формализация | Фиксированный чек-лист | Обычно ad-hoc, по ситуации |
| Вопрос | Билд вообще пригоден? | Конкретно эта правка вменяема? |
Если в вашей команде эти слова используются как синонимы — не воюйте с терминологией, договоритесь о смысле внутри команды и запишите его в тест-план. Пользы от спора о словарях меньше, чем от общего понимания.
Смоук — первый кандидат на автоматизацию
Смоук стабилен, повторяется десятки раз в неделю и имеет чёткий оракул — это идеальный профиль для скрипта. Ручным он остаётся ровно до момента, когда команда деплоит чаще, чем человек успевает его проходить.
// smoke.spec.ts — автоматизированный аналог первых пунктов чек-листа.
// Тег @smoke позволяет гонять только этот набор на каждом деплое.
import { test, expect } from '@playwright/test';
test.describe('@smoke критичный путь покупки', () => {
test('health-эндпоинт отдаёт ожидаемую версию', async ({ request }) => {
const res = await request.get('/health');
expect(res.status()).toBe(200);
const body = await res.json();
expect(body.version).toBe(process.env.RELEASE_VERSION);
expect(body.db).toBe('ok');
});
test('гость доходит от поиска до страницы оплаты', async ({ page }) => {
const errors: string[] = [];
// Консольные ошибки — дешёвый оракул, которого нет в ручном чек-листе по умолчанию.
page.on('pageerror', (e) => errors.push(e.message));
await page.goto('/');
await page.getByRole('searchbox').fill('кофе');
await page.getByRole('searchbox').press('Enter');
await expect(page.getByTestId('product-card').first()).toBeVisible();
await page.getByTestId('product-card').first().click();
await page.getByRole('button', { name: 'В корзину' }).click();
await expect(page.getByTestId('cart-count')).toHaveText('1');
await page.goto('/checkout');
await expect(page.getByTestId('payment-form')).toBeVisible();
expect(errors, `JS-ошибки на пути: ${errors.join('; ')}`).toHaveLength(0);
});
});
Детали борьбы с хрупкостью таких тестов — в https://courses.digitable.life/post/testing/07-e2e-and-ui/. Здесь важно другое: даже автоматизированный смоук остаётся гейтом, и его роль в пайплайне не меняется.
# .github/workflows/deploy.yml — смоук как блокирующий шаг между стейджем и продом
jobs:
deploy-staging:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Деплой на staging
run: ./scripts/deploy.sh staging
smoke:
needs: deploy-staging
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npx playwright install --with-deps chromium
# Только смоук-набор: он должен укладываться в единицы минут.
- name: Смоук на staging
run: npx playwright test --grep @smoke
env:
BASE_URL: https://staging.example.com
RELEASE_VERSION: ${{ github.sha }}
- uses: actions/upload-artifact@v4
if: failure()
with:
name: smoke-traces
path: test-results/
promote-to-prod:
needs: smoke # красный смоук => прод не получает билд
if: success()
runs-on: ubuntu-latest
steps:
- run: ./scripts/deploy.sh production
Подробнее про quality gates и параллелизацию — в https://courses.digitable.life/post/testing/13-tests-in-ci/.
4. Регрессионное тестирование: борьба с квадратичным ростом
Регресс отвечает на вопрос «не сломали ли мы то, что раньше работало». Проблема регресса не в сложности, а в арифметике. Каждый релиз добавляет функциональность, каждая функциональность добавляет сценарии, а время между релизами не растёт. Через два года у вас чек-лист на 900 пунктов и полторы недели на его прохождение — при недельном релизном цикле.
Дальше происходит одно из трёх, и все три плохи:
- регресс проходят «по диагонали», проставляя галочки не глядя — метрика есть, информации нет;
- регресс режут случайно («в этот раз проверим первую половину») — покрытие непредсказуемо;
- релизы замедляются под регресс — бизнес начинает считать QA тормозом, и он прав.
Правильный ответ — не проходить весь регресс, а осознанно выбирать его подмножество. Это называется Regression Test Selection и опирается на две вещи: карту изменений и карту рисков.
какие модули изменились] --> B[Карта зависимостей:
кто использует изменённое] C[История дефектов:
где баги были раньше] --> D B --> D{Ранжирование
областей по риску} E[Бизнес-критичность:
деньги, данные, репутация] --> D D --> F[Зона 1: обязательный регресс
прогоняем всегда] D --> G[Зона 2: по изменениям
прогоняем если задет модуль] D --> H[Зона 3: редкий регресс
раз в N релизов] F --> I[Бюджет времени исчерпан?] G --> I I -- нет --> H I -- да --> J[Стоп. Фиксируем,
что НЕ проверено] J --> K[Решение о релизе
принимается с этим знанием]
Последний блок — самый недооценённый. Явно сообщить, что осталось непроверенным, — часть работы тестировщика. «Регресс пройден» без указания границ — дезинформация. Формулировка вида «прошли зоны оплаты и каталога полностью, партнёрский кабинет не трогали — там изменений не было, но он не проверялся три релиза» даёт менеджеру возможность принять осознанное решение.
Простой скрипт, который переводит эту логику в приоритетный список — полезнее, чем кажется, потому что делает выбор воспроизводимым и обсуждаемым:
"""Приоритизация областей регресса: риск = вероятность x влияние, с поправкой на изменения."""
from dataclasses import dataclass, field
@dataclass
class Area:
name: str
impact: int # цена отказа: 1 (косметика) .. 5 (потеря денег/данных)
defect_history: int # число дефектов за последние N релизов
changed_now: bool # затронут ли текущим диффом
last_tested_ago: int # сколько релизов назад проверяли
manual_minutes: int # цена ручного прохода
covered_by_auto: bool = False
def probability(self) -> float:
"""Вероятность дефекта: история + факт изменения + давность проверки."""
p = 0.1 + 0.05 * min(self.defect_history, 8) # база + вклад истории, потолок 0.5
if self.changed_now:
p += 0.35 # изменённый код ломается чаще всего
p += 0.03 * min(self.last_tested_ago, 5) # гниение непроверяемых зон
return min(p, 0.95)
def risk(self) -> float:
r = self.probability() * self.impact
if self.covered_by_auto:
r *= 0.4 # автотесты снижают, но не обнуляют риск: у них свой оракул
return r
def value_per_minute(self) -> float:
"""Сколько риска снимаем за минуту ручной работы — по нему и сортируем."""
return self.risk() / max(self.manual_minutes, 1)
def plan(areas: list[Area], budget_minutes: int) -> tuple[list[Area], list[Area]]:
"""Жадный отбор под бюджет: O(n log n) по времени, O(n) по памяти.
Это вариант задачи о рюкзаке; жадность по «риск на минуту» не оптимальна
формально, но на практике точнее любого интуитивного выбора и, главное,
объяснима: всегда видно, почему область попала или не попала в план.
"""
ordered = sorted(areas, key=Area.value_per_minute, reverse=True)
selected, skipped, spent = [], [], 0
for a in ordered:
if spent + a.manual_minutes <= budget_minutes:
selected.append(a)
spent += a.manual_minutes
else:
skipped.append(a)
return selected, skipped
areas = [
Area("Оплата картой", impact=5, defect_history=6, changed_now=True,
last_tested_ago=0, manual_minutes=45),
Area("Регистрация", impact=4, defect_history=2, changed_now=False,
last_tested_ago=1, manual_minutes=25, covered_by_auto=True),
Area("Экспорт отчётов", impact=3, defect_history=5, changed_now=False,
last_tested_ago=4, manual_minutes=30),
Area("Настройки профиля", impact=1, defect_history=1, changed_now=False,
last_tested_ago=3, manual_minutes=20),
Area("Партнёрский кабинет", impact=4, defect_history=3, changed_now=True,
last_tested_ago=2, manual_minutes=60),
]
selected, skipped = plan(areas, budget_minutes=120)
print("В план:", [a.name for a in selected])
print("НЕ проверяем (сообщить команде):", [(a.name, round(a.risk(), 2)) for a in skipped])
Вывод скрипта — не «правда», а основа для разговора. Значения impact и defect_history вы берёте
из головы и из баг-трекера; ценность в том, что предположения становятся явными и их можно оспорить.
Риск-ориентированный подход подробнее разобран в https://courses.digitable.life/post/testing/00-overview/; связь с решением
«что автоматизировать» — в https://courses.digitable.life/post/testing/12-automation-strategy/.
Разработчику. Строка
covered_by_autoумножает риск на 0.4, а не на ноль — и это принципиально. Ваши юнит- и интеграционные тесты (https://courses.digitable.life/post/testing/05-unit-testing/ — см. следующий раздел курса) закрывают логику, но не закрывают вёрстку, тексты, права доступа, состояния после миграций и всё, что живёт между слоями. «Покрыто автотестами» — это снижение вероятности, а не её устранение.
5. Исследовательское тестирование: главный навык профессии
Исследовательское тестирование (ET) — это одновременное обучение продукту, проектирование тестов и их выполнение. Определение Кема Канера, автора термина, звучит именно так: три деятельности сливаются в одну петлю, где результат предыдущего действия определяет следующее.
Главное недоразумение вокруг ET: его путают с ad-hoc-тыканьем. Разница — как между импровизацией джазового музыканта и случайным нажатием клавиш. Импровизация опирается на структуру, подготовку и рефлексию. ET — тоже.
Session-Based Test Management: как сделать ET управляемым
Главное возражение менеджмента против ET — «это неуправляемо, я не вижу, что происходит». Ответ на него придумали Джеймс и Джон Бах в 2000 году: SBTM (Session-Based Test Management). Идея — упаковать исследование в учётные единицы.
Единица работы — сессия: непрерывный таймбокс 45–120 минут (обычно 90) под одним чартером, без переключений на почту и митинги. Всё время сессии делится на три категории, которые называются метрикой T/B/S:
- S (Setup) — подготовка окружения, данных, доступов;
- T (Test design & execution) — собственно исследование;
- B (Bug investigation & reporting) — воспроизведение, локализация, оформление находок.
Эта разбивка — не бюрократия, а диагностический инструмент. Если из сессии в сессию S съедает 40% времени, у вас проблема не с тестированием, а с тестовыми данными и окружением, и её решение окупится быстрее любого автотеста. Если B стабильно 50% — продукт сыпется, и стоит говорить с командой о качестве входящего билда, а не наращивать часы QA.
Чартер — миссия сессии на одно-два предложения. Хороший шаблон (Элизабет Хендриксон, «Explore It!»):
Исследовать (целевая область) с помощью (ресурсы, техники, данные) чтобы обнаружить (какого рода информацию).
Примеры рабочих чартеров:
- Исследовать импорт CSV с помощью битых, огромных и экзотически закодированных файлов, чтобы обнаружить потерю данных и зависания UI.
- Исследовать права ролей admin/manager/viewer с помощью прямых запросов к API в обход UI, чтобы обнаружить обход авторизации.
- Исследовать корзину с помощью двух вкладок одного пользователя, чтобы обнаружить гонки и рассинхронизацию состояния.
Сравните с плохим чартером «протестировать корзину»: у него нет ни ресурса, ни типа искомой информации, и по нему невозможно понять, когда сессия закончена.
Отчёт сессии
Отчёт — не пересказ действий, а сжатая информация для команды. Формат, который реально читают:
# Session Report
CHARTER
Исследовать импорт CSV с помощью битых и огромных файлов,
чтобы обнаружить потерю данных и зависания UI.
BUILD / ENV
RC-2.14 (sha 8f21a0c), staging, Chrome 138, macOS 15.2
AREAS
ui/import-dialog, api/POST /v1/import, worker/csv-parser, db/staging_rows
START / DURATION
2026-07-16 11:00 / 90 мин
TASK BREAKDOWN
S 20% | T 50% | B 30%
On-charter 85% / Off-charter 15% (ушёл в экспорт — там смежный риск)
DATA FILES
fixtures/csv/*.csv (см. вложение), генератор gen_csv.py
BUGS
BUG-412 Файл 200 МБ вешает вкладку без индикатора, таймаута нет
BUG-413 UTF-8 BOM превращает первую колонку в «п»»їid», строки молча теряются
ISSUES (не баги, а препятствия и вопросы)
- Нет способа увидеть статус импорта после закрытия вкладки
- Непонятно, каково ожидаемое поведение для дублей по внешнему ключу — спросить у продакта
- На staging нельзя загрузить файл > 250 МБ (лимит nginx), риск не проверен
NOTES
Парсер разваливается на кавычках внутри кавычек (RFC 4180 §2.7) —
не воспроизвёл стабильно, нужен отдельный чартер.
Строка ISSUES часто ценнее строки BUGS: она содержит риски, которые ещё не стали дефектами,
и вопросы к спецификации. Именно там появляется работа для аналитика и продакта.
Эвристики: чем заполняется голова во время сессии
Исследование без техник вырождается в хаотичное кликанье. Три набора, которые стоит знать наизусть.
SFDIPOT (San Francisco Depot) — модель продукта Бача: по каким осям вообще можно его разрезать.
| Ось | Что смотреть | |
|---|---|---|
| S | Structure | Из чего собран: файлы, модули, сервисы, железо |
| F | Function | Что умеет: расчёты, вычисления, обработка ошибок, UI |
| D | Data | Что обрабатывает: входы, выходы, размеры, кодировки, время жизни, кардинальность |
| I | Interfaces | Как с ним говорят: UI, API, файлы, импорт/экспорт |
| P | Platform | На чём живёт: ОС, браузеры, сеть, зависимости, локали |
| O | Operations | Как используют: типичные и экстремальные сценарии, роли |
| T | Time | Как влияет время: одновременность, таймауты, часовые пояса, порядок |
Практика: выпишите семь букв в столбик и задайте по одному вопросу к каждой. Ось Time и ось Data дают больше всего продакшн-багов и чаще всего пропускаются.
Туры Уиттакера (из «Exploratory Software Testing») — способы обойти продукт с заданной ролью:
- Guidebook tour — делаете строго то, что написано в документации. Расхождения — баги (оракул Claims).
- Money tour — проходите только тем путём, которым приходят деньги. Здесь самая высокая цена дефекта.
- Landmark tour — выбираете 5–7 «достопримечательностей» и ходите между ними в случайном порядке. Ломает предположения о линейности потока.
- Back alley tour — идёте в самые непопулярные фичи. Там меньше всего тестировали.
- Supermodel tour — смотрите только на внешний вид, не на логику: вёрстка, тексты, состояния загрузки.
- Saboteur / anti-social tour — делаете всё, чего от вас не ждут: назад в браузере, двойные клики, отключение сети посреди операции, ввод emoji в поле «возраст».
Галлюмбир (Goldilocks) и границы — на любое поле применяйте «слишком мало / в самый раз / слишком много», а на любую последовательность — «прервать посередине». Это дёшево, механично и находит огромную долю дефектов. Формальная версия этой техники — граничные значения из https://courses.digitable.life/post/testing/02-test-design/.
Парное и групповое исследование
Два приёма, которые дают непропорционально много:
- Парное тестирование (тестировщик + разработчик за одним экраном, 60 минут). Тестировщик видит странность, разработчик тут же смотрит в код и говорит «а, здесь у нас race condition» — цикл обратной связи схлопывается с дней до секунд. Побочный эффект: разработчик перестаёт считать QA формальностью.
- Bug bash — вся команда (включая продакта, дизайнера, поддержку) на 60–90 минут садится ломать фичу перед релизом, каждый со своим чартером. Люди с разным контекстом видят разное; поддержка находит то, чего не видит никто, потому что помнит реальные обращения.
6. Приёмочное тестирование: вопрос про деньги
Приёмочное тестирование (UAT, User Acceptance Testing) отвечает не на вопрос «есть ли баги», а на вопрос «принимаем ли мы эту работу». Отсюда все его особенности:
- решение принимает заказчик или его представитель, не QA и не разработка;
- проверяются бизнес-сценарии целиком, а не функции по отдельности;
- критерии приёмки формулируются до начала разработки — иначе приёмка превращается в торг;
- дефекты, найденные здесь, стоят максимально дорого: продукт уже сделан.
Ключевой момент этой схемы — шаг «разделить: дефекты vs пожелания». На UAT всегда всплывают идеи «а хорошо бы ещё». Если не разделять их с дефектами, приёмка не заканчивается никогда. Практическое правило: дефект — это расхождение с зафиксированным критерием; всё остальное — новая работа и идёт в бэклог с обычной приоритизацией.
Критерии приёмки удобно писать в формате Given/When/Then — тот же язык, что используется в BDD (https://courses.digitable.life/post/testing/14-tdd-and-bdd/), даже если Cucumber вы не берёте:
Функция: Возврат средств по заказу
Сценарий: Полный возврат в течение 14 дней
Дано заказ №A-1042 оплачен картой 10 дней назад на сумму 12 480 ₽
И статус заказа «Доставлен»
Когда оператор оформляет полный возврат с причиной «Не подошёл размер»
Тогда в платёжной системе создаётся возврат на 12 480 ₽
И статус заказа меняется на «Возврат оформлен»
И клиенту уходит письмо с суммой и сроком зачисления
И в бухгалтерской выгрузке за день появляется соответствующая строка
Обратите внимание на последнюю строку: приёмочные критерии почти всегда выходят за пределы UI. Проверка «письмо ушло» и «выгрузка сошлась» — это и есть отличие приёмки от функционального теста.
Соседние формы приёмки
- Альфа — тестирование силами внутренних пользователей на рабочем окружении.
- Бета — ограниченная группа реальных пользователей. Главная ценность — не поиск багов, а обнаружение того, что люди используют продукт не так, как вы задумали.
- Operational Acceptance Testing (OAT) — приёмка со стороны эксплуатации: разворачивается ли, откатывается ли, есть ли мониторинг, работает ли бэкап и восстановление из него. Регулярно забывают, а потом узнают о проблеме в три часа ночи. Смежная тема — https://courses.digitable.life/post/devops/00-overview/.
- Приёмка по контракту — когда критерии зафиксированы юридически, и от вердикта зависит оплата этапа. Здесь особенно важно, чтобы критерии были измеримыми: «система должна работать быстро» — не критерий, «95-й перцентиль ответа поиска < 800 мс при 200 RPS» — критерий (как это меряют — в https://courses.digitable.life/post/testing/09-performance-testing/).
7. Что оставлять человеку: экономика решения
Ручной час стоит денег и не масштабируется. Автоматизация стоит денег на разработку и на поддержку, но масштабируется. Решение принимается по двум осям: как часто проверка повторяется и насколько стабилен её оракул.
Грубая, но работающая прикидка окупаемости. Ручной прогон сценария стоит M минут и повторяется N
раз в год. Автоматизация того же сценария — A минут разработки плюс S минут поддержки за прогон
(починка селекторов, обновление данных, разбор флаки). Автоматизация выгодна, когда
N × M > A + N × S. Отсюда два часто игнорируемых следствия.
Первое. При S, сравнимом с M, автоматизация не окупается никогда. Хрупкий E2E-тест, который каждый
третий прогон требует пятиминутного разбора «упало по делу или флак», может стоить дороже ручной проверки.
Это не аргумент против автоматизации — это аргумент за то, чтобы считать S честно.
Второе. Сценарий, который выполняется дважды в год, автоматизировать почти никогда не нужно, даже если это технически легко. Классический пример — ежегодная процедура закрытия финансового года.
Разработчику vs тестировщику: где взгляды расходятся. Разработчик почти всегда переоценивает покрытие автотестами и недооценивает стоимость поддержки — потому что видит логику, а не продукт целиком. Тестировщик чаще недооценивает выгоду автоматизации регресса и переоценивает ценность ручного повторения — потому что ручной прогон ощущается как «настоящая работа». Полезное упражнение для обеих сторон: разработчик проводит одну 90-минутную исследовательскую сессию по чужой фиче, тестировщик читает и правит один автотест. После этого спор становится содержательным.
8. Типичные ошибки
- Ручной регресс без бюджета и приоритетов. Приводит к «прохождению по диагонали». Лечится риск-ранжированием и явным сообщением о непроверенном.
- Смоук, который нельзя провалить. Если после красного смоука тестирование всё равно продолжается — это не гейт, а ритуал. Уберите его или дайте ему право блокировать.
- ET без чартера и таймбокса. Превращается в бесцельное кликанье, о котором нельзя отчитаться. Полтора часа под конкретной миссией дают больше, чем день свободного плавания.
- Пошаговые сценарии там, где нужен чек-лист. Инструкция «нажмите → введите → нажмите» отключает мышление: человек выполняет шаги и не смотрит по сторонам. Для опытного тестировщика формулируйте цель, а не маршрут.
- Отчёт «проверил, всё ок». Не содержит информации. Что именно проверено, на каком билде, в каком окружении, что осталось за кадром — вот содержание отчёта.
- Тестирование на «удобных» данных. Пользователь
Тест Тестовс адресомул. Тестовая, 1никогда не найдёт баг с фамилией из двух слов, апострофом вO'Brien, адресом на 200 символов или именем на арабском. Заведите набор «злых» данных и используйте его всегда. - Приёмка без заранее зафиксированных критериев. Превращается в переговоры о том, что вообще считать готовым.
- Ручная проверка того, что уже проверяет CI. Двойная оплата за одну и ту же информацию. Перед каждым ручным сценарием стоит спросить: «этого правда нет ни в одном автотесте?»
9. Инструменты, которые превращают клики в информацию
Ручное тестирование «мышкой и глазами» — самый слабый его вариант. Минимальный набор, отличающий инженера от кликера:
- DevTools: вкладка Network (какой запрос ушёл, что вернулось, сколько занял), Console (JS-ошибки), Application (куки, localStorage, сессия), device toolbar и троттлинг сети — половина находок «фронтендных» багов на самом деле находится здесь.
- HTTP-прокси — Proxyman, Charles, mitmproxy. Позволяют подменить ответ сервера и посмотреть, как UI переживёт 500, пустой массив или таймаут. Проверки, недоступные через интерфейс.
- Логи и трейсы — доступ к логам приложения во время сессии превращает «что-то не сработало» в «упало вот здесь со вот этим исключением». Разница в скорости починки — на порядок.
- SQL-доступ к тестовой базе — проверить, что реально записалось, а не что показал экран.
- Генераторы данных — Faker, собственные скрипты. Ручной ввод двадцати записей — потерянное время.
- Инструменты записи: скринкаст (баг с гонкой невозможно описать словами), сбор HAR-файла, Playwright trace viewer — прикладывать к баг-репорту.
- Заметки — от текстового файла до mind map. Сессия без заметок теряет 70% находок: память не удерживает контекст исследования дольше нескольких минут.
Мини-итог
- Автоматизировать можно только уже сформулированные ожидания. Человек нужен там, где оракул нечёткий: проблема оракула — фундаментальная, а не временная.
- Смоук — короткий широкий гейт с правом блокировать; отвечает «билд пригоден?». Первый кандидат на автоматизацию.
- Регресс растёт неограниченно; его не проходят целиком, а выбирают по риску и явно сообщают, что осталось непроверенным.
- Исследовательское тестирование — не хаос, а управляемая практика: чартер, таймбокс, сессия, метрика S/T/B, отчёт, дебриф. Эвристики HICCUPPS, SFDIPOT и туры — рабочий инструментарий, а не теория.
- Приёмка отвечает на вопрос о деньгах, решается заказчиком и требует критериев, зафиксированных до разработки.
- Решение «руками или скриптом» — экономическое:
N × M > A + N × S, гдеS(поддержка) почти всегда недооценивают.
Что дальше
Мы разобрали, что человек делает с продуктом целиком. Дальше спускаемся на уровень кода: как проверять отдельные единицы логики быстро, изолированно и так, чтобы тесты не превратились в обузу при первом же рефакторинге — Модульные тесты: изоляция, тестовые дублёры, что такое хороший юнит-тест.
Источники и что почитать:
- James Bach, Jonathan Bach. Session-Based Test Management
- Michael Bolton. FEW HICCUPPS — оракулы
- Elisabeth Hendrickson. Explore It! Reduce Risk and Increase Confidence with Exploratory Testing
- James Whittaker. Exploratory Software Testing — туры по продукту
- Cem Kaner, James Bach, Bret Pettichord. Lessons Learned in Software Testing — 293 урока практики
- Rapid Software Testing — методология Бача и Болтона, бесплатные материалы