Зачем нужно тестирование
Разбираемся, почему компании платят людям за то, чтобы те искали проблемы в их же продукте, и почему «поиск багов» — далеко не главная часть этой работы.
Тестирование — это способ получить информацию о качестве продукта, чтобы человек, отвечающий за релиз, мог принять осознанное решение: выпускать, доделывать или откладывать. Найденные дефекты — побочный продукт, а не цель.
Первое, что слышит новичок: «тестировщик ищет баги». Формально верно — примерно так же, как «врач выписывает таблетки». Таблетки — это то, что видно пациенту; работа врача — понять, что происходит, и снизить неопределённость. У тестировщика ровно так же. Багрепорт — видимый результат. Настоящий результат — ответ на вопрос «что мы знаем про эту версию продукта и чего мы про неё не знаем».
Чтобы этот тезис не звучал как красивая фраза с собеседования, начнём с денег.
Дефект дешевеет только в одну сторону — назад
Одна и та же ошибка стоит компании принципиально по-разному в зависимости от того, на каком этапе её заметили. Дело не в том, что «поздно» править код труднее — строчка меняется одинаково быстро. Дело в том, что поверх ошибки уже успели построить: код, тесты, документацию, интеграции с соседними командами, обученную поддержку и, самое неприятное, данные живых пользователей в базе.
| Где нашли дефект | Что значит «исправить» | Порядок цены |
| Требования, до кода | Переписать абзац в постановке, поспорить 15 минут на груминге | ×1 |
| Дизайн и архитектура | Перерисовать макет, пересогласовать схему данных | ×5 |
| Разработка, до слияния ветки | Разработчик правит свой же свежий код, контекст в голове | ×10 |
| Тестирование | Багрепорт, переключение контекста разработчика, повторный прогон регресса, сдвиг сроков | ×15–40 |
| Продакшн | Хотфикс, откат, миграция испорченных данных, обращения в поддержку, репутация, иногда прямые убытки | ×100 и выше |
Точные множители спорны — их измеряли в разных компаниях с разными результатами, и любая цифра здесь условна. Но порядок величины подтверждается практикой везде: чем позже, тем дороже, и рост нелинейный.
Совсем конкретно. Аналитик написал «поле email — необязательное». Никто не задал вопрос. Дальше: разработчик сделал колонку nullable, маркетолог построил на этих данных рассылку, в базе накопилось 200 тысяч аккаунтов без почты. Через полгода бизнес говорит: «нам нужно восстановление пароля». Исправить это в требованиях стоило бы одного вопроса тестировщика: «а как человек будет восстанавливать доступ?» Исправить в продакшне — это миграция данных, кампания по дособиранию почт, поддержка, которая полгода будет разгребать «не могу войти».
Именно поэтому хороший тестировщик страшно любит задавать вопросы к тексту, а не только тыкать кнопки. Вопрос к требованию — самый дешёвый баг в мире.
Пять дефектов, которые стоили дороже целой карьеры
Эти истории стоит знать не ради эрудиции. В каждой видна конкретная дыра в тестировании, которую вы будете встречать всю жизнь — только в масштабе своего продукта.
| Случай | Что произошло | Цена | Урок для тестировщика |
| Therac-25, 1985–1987 | Аппарат лучевой терапии. Если оператор очень быстро правил введённые параметры, срабатывала гонка состояний (race condition) и пациент получал дозу в сотни раз выше назначенной. Аппаратные блокировки в новой модели убрали, положившись на программу. | Тяжёлые поражения и смерти пациентов | Компоненты по отдельности «работали». Сценарий «оператор печатает быстро и ошибается» никто не проверял. |
| Ariane 5, полёт 501, 1996 | Инерциальную систему переиспользовали от Ariane 4. При конвертации 64-битного числа с плавающей точкой в 16-битное целое произошло переполнение, бортовой компьютер выдал мусор вместо навигации, ракета отклонилась и самоликвидировалась примерно на 40-й секунде. | Около 370 млн долларов | Переиспользованный код в НОВОМ контексте — это новый код. Старые тесты про новые условия ничего не знают. |
| Mars Climate Orbiter, 1999 | Один модуль считал импульс в фунт-силах-секундах, другой ожидал ньютон-секунды. Аппарат вошёл в атмосферу Марса слишком низко и погиб. | Сотни миллионов долларов миссии | Классический интеграционный дефект: каждый модуль «правильный», ошибка живёт на стыке. Проверяйте контракты между системами. |
| Knight Capital, 2012 | При выкатке новый код попал на семь серверов из восьми. На восьмом ожил старый флаг, переиспользованный под новую функцию, и торговый робот начал безумно скупать и сбрасывать акции. | Около 440 млн долларов за 45 минут; компания фактически перестала существовать | Тестировать нужно не только код, но и процесс релиза, откат и работу в «смешанном» состоянии версий. |
| Heartbleed, OpenSSL, 2014 | Сервер не проверял, что заявленная длина в служебном запросе совпадает с реальной, и вежливо отдавал в ответ кусок собственной памяти — с ключами и паролями. Уязвимость прожила в коде около двух лет. | Сотни тысяч затронутых серверов по всему миру | «Работает» не равно «безопасно». Позитивные проверки эту дыру не видят — нужны негативные и граничные. |
Обратите внимание: почти нигде причина не в «программист не умеет писать код». Причины — гонки, стыки, переиспользование, релизная процедура, отсутствие проверок на некорректный ввод. Всё это территория тестировщика.
Тестирование ничего не гарантирует — оно снижает неопределённость
Тестирование может показать наличие дефектов, но не может доказать их отсутствие. Эдсгер Дейкстра
Это не пессимизм, а математика. Представьте обычную форму регистрации: имя, email, пароль, возраст, страна, валюта, галочка согласия. Даже если для каждого поля взять не все возможные значения, а всего несколько классов («пусто», «валидное», «слишком длинное», «спецсимволы»), количество комбинаций взрывается.
# «Давайте просто проверим все комбинации» — считаем, во что это обойдётся
polya = {
"имя": 4,
"email": 5,
"пароль": 6,
"возраст": 5,
"страна": 200,
"валюта": 15,
"согласие": 2,
}
kombinacii = 1
for pole, klassov in polya.items():
kombinacii *= klassov
sekund_na_proverku = 30
vsego_sekund = kombinacii * sekund_na_proverku
print("Комбинаций:", kombinacii)
print("Часов ручной проверки:", round(vsego_sekund / 3600, 1))
print("Лет непрерывной работы:", round(vsego_sekund / (3600 * 24 * 365), 2))
Результат:
Комбинаций: 3600000
Часов ручной проверки: 30000.0
Лет непрерывной работы: 3.42
Три с половиной года без сна и обеда — на одну форму. А ведь мы не трогали браузеры, разрешения экрана, порядок действий и состояние сети. Вывод жёсткий и очень практичный: исчерпывающее тестирование невозможно. Значит, работа тестировщика — это всегда выбор: что проверить в те два дня, что у нас есть, чтобы узнать самое важное.
Как выбирать: риск = вероятность × ущерб
Инструмент выбора один и тот же на любом проекте. Прикидываем для каждой функции две вещи: насколько вероятно, что она сломана, и насколько больно будет, если она сломается у пользователя.
| Функция интернет-магазина | Вероятность дефекта | Ущерб | Приоритет |
| Оплата картой | Средняя (много интеграций) | Катастрофа: потерянные деньги и доверие | P0 — проверяем всегда |
| Оформление заказа | Средняя | Высокий: нет заказа — нет выручки | P0 |
| Поиск по каталогу | Высокая (часто меняют) | Средний: люди уйдут, но не сразу | P1 |
| История заказов | Низкая | Средний | P2 |
| Смена аватара в профиле | Низкая | Низкий | P3 — если останется время |
Если вы потратили три часа на автотесты аватарки, пока оплата через новый эквайринг не проверена ни разу, — вы отработали честно и при этом абсолютно бесполезно.
Что на самом деле является продуктом вашей работы
Сравните две реплики тестировщика на релизной встрече.
Плохо:
«Я всё протестировал, багов нет, можно катить.»
Хорошо:
«Проверил 34 сценария из 40 запланированных. Критичных дефектов нет.
Открыты два средних: не сохраняется адрес доставки при смене города,
и на iOS съезжает кнопка оплаты (косметика).
НЕ проверялась оплата через СБП — нет тестового контура.
Это примерно 30% наших платежей: если там сломано, узнаем от клиентов.
Решение о релизе — за вами.»
Первая фраза ничего не даёт менеджеру и вдобавок перекладывает на тестировщика ответственность, которую он не может нести. Вторая — это готовая опора для решения: видно, что проверено, что не проверено, где риск и чем он измеряется в деньгах. Вот это и есть продукт вашей работы. Не баги. Информация.
Как это работает
Любая проверка, от ручного клика до автотеста, устроена одинаково:
- Риск — предположение, что здесь может быть сломано.
- Выбор проверки — какой сценарий и с какими данными покажет, так это или нет.
- Выполнение — прогоняем.
- Наблюдение — что произошло на самом деле.
- Сравнение с оракулом — а как должно было быть?
- Интерпретация и отчёт — это дефект? насколько важный? что это говорит о качестве в целом?
Ключевой и самый недооценённый пункт — пятый. Оракул — это источник знания о том, каким должно быть правильное поведение. Оракулом может быть требование, макет, поведение прежней версии, аналогичный продукт конкурента, стандарт, закон, здравый смысл или внутренняя непротиворечивость («на карточке товара цена 990, а в корзине 1090 — что-то одно врёт»). Если у вас нет оракула, у вас нет теста: вы просто нажимаете на кнопки и смотрите, что будет. Это называется «потыкать», и это тоже иногда полезно, но путать одно с другим нельзя.
Частые ошибки
- «За качество отвечает тестировщик». Нет. За качество отвечает вся команда, включая разработчиков, аналитика и продакта. Тестировщик отвечает за достоверность и полноту информации о качестве. Разница принципиальная: во втором случае вас невозможно сделать крайним за чужое решение «катим как есть».
- «Мы всё протестировали». Так не бывает — см. расчёт выше. Говорите конкретно: что покрыто, что нет, что осталось за скобками.
- Гнаться за числом найденных дефектов. Как только «баги в месяц» становятся метрикой, в трекер потоком идёт мусор про отступы, а тяжёлые сценарии никто не трогает — они долгие и в них можно ничего не найти.
- Проверять только счастливый путь. Пользователь обязательно введёт минус в поле «количество», нажмёт «Оплатить» дважды и выключит Wi-Fi посередине. Heartbleed и Therac-25 — как раз про это.
- Держать риски в голове. Не записанный и не озвученный риск для команды не существует. Если вы «вроде подозревали», но никому не сказали — вы не сделали свою работу.
- Начинать тестировать, когда код готов. Самые дорогие дефекты рождаются в требованиях, а там ещё нечего кликать — там нужно читать и спрашивать.
Итоги
- Тестирование существует не ради багов, а ради информации для решения о релизе.
- Цена дефекта растёт нелинейно: дешевле всего он стоит в требованиях, дороже всего — у пользователя.
- Исчерпывающее тестирование математически невозможно, поэтому главный навык — приоритизация по риску (вероятность × ущерб).
- Каждая проверка требует оракула — понимания, как должно быть. Без него это не тест.
- Хороший отчёт всегда говорит и о том, что не проверено, — это часть информации, а не признание в слабости.
- Легендарные катастрофы почти всегда про стыки, гонки, переиспользование и релизные процедуры, а не про «плохой код».