Принципы и терминология: верификация, валидация, дефект, качество
Есть соблазн пролистать статью про термины: «ну баг и баг, все понимают». Проблема в том, что не понимают — и расхождение стоит денег. Типичный диалог на ретро:
— Мы всё протестировали, качество высокое. — А почему клиент вернул релиз? — Так это не баг, это требование такое было. — Требование было неправильное. — Ну это не к нам.
Здесь в четырёх репликах перепутаны верификация и валидация, дефект и несоответствие требованию, качество продукта и качество в использовании. Пока команда не различает эти вещи словами, она не различает их и действиями: не проверяет требования, не заводит дефекты на спецификацию, меряет качество числом закрытых тикетов.
Эта статья — фундамент курса. Дальше будут техники (https://courses.digitable.life/post/testing/02-test-design/), документация (https://courses.digitable.life/post/testing/03-documentation/), инструменты. Здесь — понятийная сетка, на которую всё это ложится, плюс честный разбор, где красивые определения из учебников ломаются о практику.
Ошибка, дефект, сбой: три разные вещи
Самая полезная различающая триада. Она зафиксирована в IEEE 1044 и в глоссарии ISTQB, но важна не как формальность, а как способ думать.
- Error / Mistake (ошибка) — действие человека, породившее неправильный результат. Разработчик неверно понял требование, перепутал
<и<=, забыл про часовой пояс. Ошибка живёт в голове и в моменте. - Defect / Fault / Bug (дефект) — материальный след ошибки в артефакте: в коде, в конфиге, в требовании, в схеме БД, в тексте на кнопке. Дефект существует в репозитории, даже если его никто не наблюдал.
- Failure (сбой, отказ) — наблюдаемое отклонение поведения системы от ожидаемого при исполнении. Сбой существует во времени выполнения.
Важнейший вывод: дефект не обязан приводить к сбою, и один дефект может порождать десятки разных сбоев. Мы находим дефекты через сбои — но между ними стоит цепочка условий.
Эту цепочку в академической литературе называют моделью RIP (Reachability, Infection, Propagation) — она подробно разобрана в Ammann & Offutt, Introduction to Software Testing. Чтобы тест нашёл дефект, должны выполниться три условия:
- Reachability — тест должен дойти до дефектного кода;
- Infection — состояние программы после исполнения должно стать неверным;
- Propagation — искажение должно дойти до наблюдаемого выхода, и проверка должна его заметить.
Разберём на коде — это самый быстрый способ понять, почему «100% покрытия» ничего не гарантирует.
def apply_discount(price: float, percent: int) -> float:
"""Возвращает цену со скидкой. Дефект: нет верхней границы процента."""
if percent < 0: # проверяем только нижнюю границу
percent = 0
return price * (100 - percent) / 100
# Тест 1: строка с дефектом выполняется (Reachability есть),
# но состояние корректно — Infection нет. Тест зелёный.
def test_normal_discount():
assert apply_discount(100.0, 10) == 90.0
# Тест 2: Reachability + Infection (percent=150 даёт -50.0),
# но мы проверяем только тип — Propagation до проверки не доходит. Тест зелёный.
def test_returns_float():
assert isinstance(apply_discount(100.0, 150), float)
# Тест 3: все три условия выполнены — сбой наблюдаем.
def test_discount_above_100_is_clamped():
assert apply_discount(100.0, 150) == 0.0 # падает: получаем -50.0
Покрытие строк во всех трёх случаях одинаковое — 100%. Дефект находит только третий тест. Отсюда правило, к которому мы вернёмся в https://courses.digitable.life/post/testing/13-tests-in-ci/: покрытие измеряет Reachability и ничего больше. Это метрика достижимости, а не метрика качества проверок. Мутационное тестирование, наоборот, бьёт прямо в Infection + Propagation — потому и честнее.
Разработчику: триада объясняет, почему «у меня локально работает» — не аргумент. Отсутствие сбоя не означает отсутствия дефекта, оно означает, что вы не подобрали данные, вызывающие Infection.
Тестировщику: триада объясняет, почему баг-репорт «иногда падает» бесполезен. Ваша работа — не только зафиксировать Failure, но и сузить условия до воспроизводимого набора данных, приближающего разработчика к Fault.
Верификация и валидация: два разных вопроса
Классическая формулировка принадлежит Барри Боэму:
- Верификация — Are we building the product right? Соответствует ли то, что мы сделали, тому, что мы записали: спецификации, требованиям, дизайну, стандарту, контракту API.
- Валидация — Are we building the right product? Решает ли то, что мы сделали, реальную задачу реального пользователя.
Разница не академическая. Верификация всегда идёт относительно документа, валидация — относительно потребности. Система может пройти верификацию на 100% и провалить валидацию полностью: идеально реализованная неправильная идея.
Это V-модель — не как процесс разработки (в таком виде она давно мертва), а как карта соответствий: каждый уровень проверки отвечает своему уровню спецификации. Ценность идеи сохраняется и в Agile: приёмочный тест всё равно проверяет потребность, а модульный — реализацию.
Практические следствия:
| Приём | Что это | Верификация или валидация |
|---|---|---|
| Код-ревью | Сверка кода со стандартом и дизайном | Верификация |
| Статический анализ, линтеры | Сверка кода с правилами | Верификация |
| Модульные и интеграционные тесты | Сверка поведения с ожидаемым по спеке | Верификация |
| Контрактные тесты | Сверка API с контрактом | Верификация |
| Ревью требований с аналитиком | Сверка требований между собой | Верификация требований |
| Демо заказчику, UAT | Проверка, решена ли задача | Валидация |
| A/B-тест, пользовательские интервью | Проверка гипотезы о ценности | Валидация |
| Бета-тест, канареечный релиз | Проверка на реальном трафике | Валидация |
Обратите внимание: большая часть того, что команды называют «тестированием», — это верификация. Валидация делается редко, поздно и часто вообще не тестировщиками, а продактами. Отсюда системный перекос: команда уверена, что «протестировала», а продукт не нужен.
Где расходятся взгляды. Разработчик обычно считает валидацию не своей зоной («мне дали задачу — я сделал»). Тестировщик, наоборот, часто оказывается единственным человеком, который читает требование целиком и замечает, что оно противоречит другому требованию или здравому смыслу. Это и есть главная недооценённая ценность QA: тестирование требований до написания кода дешевле тестирования кода. Обнаруженное на ревью требований противоречие стоит часа обсуждения; то же противоречие, найденное в проде, стоит инцидента.
Что такое качество (и почему определение важнее, чем кажется)
Три классических определения, между которыми стоит выбирать сознательно:
- Филип Кросби: качество — соответствие требованиям (conformance to requirements). Удобно измерять, но делает бессмысленным вопрос «а требования хорошие?».
- Джозеф Джуран: качество — пригодность к использованию (fitness for use). Ближе к реальности, но измерять сложно.
- Джеральд Вайнберг: «Quality is value to some person» — качество есть ценность для кого-то конкретного. Самое честное: оно требует назвать этого человека. Джеймс Бах позже добавил уточнение: «…at some time who matters» — ценность для того, чьё мнение влияет на судьбу продукта.
Определение Вайнберга — рабочий инструмент, а не философия. Когда на груминге спорят «это баг или не баг», правильный вопрос: для кого это потеря ценности и насколько эта потеря значима? Ответ обычно закрывает спор за минуту.
Индустриальный стандарт раскладывает качество на измеримые характеристики — ISO/IEC 25010 (редакция 2023 года, часть серии SQuaRE).
Три вещи, ради которых эту модель стоит держать в голове:
- Качество — вектор, а не число. «Качественный продукт» — бессмысленная фраза, пока не сказано, по каким осям. Банковский бэкенд оптимизирует надёжность и безопасность; прототип для инвестора — функциональную полноту и скорость выхода; встроенное ПО кардиостимулятора — safety, ценой всего остального.
- Тестируемость — часть сопровождаемости. То есть свойство продукта, а не тестировщика. Если систему невозможно проверить, это дефект архитектуры. Требовать тестируемости — законное инженерное требование, а не каприз QA.
- Качество в использовании — отдельная модель. Продукт может быть безупречен по всем девяти характеристикам и всё равно не решать задачу. Это ровно граница между верификацией и валидацией, только выраженная в терминах стандарта.
Ссылки на первоисточники: ISO/IEC 25010, ISTQB Glossary (бесплатный, поддерживает русский), IEEE 1044-2009.
QA, QC, тестирование, отладка — четыре разных занятия
Слова часто используют как синонимы, а это разные виды работ с разными владельцами.
- QA (обеспечение качества) — работа с процессом: как организовать разработку, чтобы дефектов возникало меньше. Definition of Done, обязательное ревью, стандарты, шаблоны, разбор инцидентов. Превентивно.
- QC (контроль качества) — работа с продуктом: проверить готовый артефакт и найти в нём дефекты. Реактивно.
- Тестирование — конкретная техника QC: исполнение системы (динамическое) или анализ артефакта (статическое) с целью обнаружить несоответствие.
- Отладка — поиск и устранение причины сбоя. Это работа разработчика, а не тестировщика: тестировщик находит Failure, разработчик — Fault.
Практический смысл различения: должность «QA-инженер», занимающаяся исключительно прогоном тест-кейсов, на самом деле QC. Это не унизительно, но объясняет, почему в таких командах количество дефектов не падает год за годом — никто не работает с процессом.
Семь принципов тестирования — и что с ними не так
Канонический список из ISTQB Foundation Level. Он полезен, но каждый пункт стоит читать вместе с оговоркой.
1. Тестирование показывает наличие дефектов, а не их отсутствие. Дейкстра: «Program testing can be used to show the presence of bugs, but never to show their absence». Тестирование — эмпирическая, а не доказательная деятельность. Оговорка: формальная верификация и типы всё-таки доказывают отсутствие целых классов дефектов. Строгая типизация, Option вместо null, тотальные функции — это способ сделать дефект невыразимым, а не ловить его тестом. См. https://courses.digitable.life/post/principles/06-testing-principles/.
2. Исчерпывающее тестирование невозможно. Функция от двух 32-битных чисел имеет порядка 1.8×10^19 комбинаций входов. Даже тривиальная форма из 10 полей даёт комбинаторный взрыв. Отсюда вся дисциплина тест-дизайна — выбирать разумное подмножество. Оговорка: «невозможно» относится к перебору; фаззинг и property-based тестирование покрывают гигантские пространства входов автоматически и находят то, что человек не придумает.
3. Раннее тестирование экономит время и деньги (shift left). Дефект, найденный на этапе требований, дешевле дефекта в проде на порядки. Оговорка: знаменитая «кривая Боэма» с ростом стоимости в 100 раз происходит из данных 1970-х по waterfall-проектам и многократно критиковалась (см. разбор Лорана Боссавита, The Leprechauns of Software Engineering). Направление верное, конкретные множители — фольклор. Не цитируйте «×100» как факт.
4. Кластеризация дефектов. Небольшое число модулей содержит большинство дефектов — принцип Парето в действии. Практический вывод: история багов — лучший источник для приоритизации тестов. Модуль, в котором за квартал нашли 12 дефектов, почти наверняка даст тринадцатый.
5. Парадокс пестицида. Одни и те же тесты со временем перестают находить новое — как насекомые вырабатывают устойчивость к пестициду. Регрессионный набор нужно обновлять, добавлять новые техники, менять данные. Оговорка: это не значит, что старые тесты бесполезны — они переходят из режима «поиск дефектов» в режим «защита от регрессий». Две разные функции с разной ценностью.
6. Тестирование зависит от контекста. Медицинский софт, банковский процессинг, игра и внутренний дашборд тестируются принципиально по-разному. Нет универсально правильной стратегии — есть подходящая под риски.
7. Заблуждение об отсутствии ошибок. Система без известных дефектов может быть непригодной. Это принцип 1 плюс принцип «валидация ≠ верификация», сформулированный для менеджмента.
К этим семи стоит добавить два принципа, которых в ISTQB нет, но которые определяют реальную работу:
8. У тестирования есть цена, и она конкурирует с ценностью. Каждый тест стоит: написать, прогонять, поддерживать при рефакторинге, чинить когда флакует. Тест, который за год ни разу не поймал дефект и трижды упал ложно, — отрицательная ценность. Решение «что тестировать» — экономическое, а не моральное. Подробно в https://courses.digitable.life/post/testing/12-automation-strategy/.
9. Тесты — тоже код, и в них тоже есть дефекты. Зелёный тест может быть зелёным потому, что ничего не проверяет (см. пример с isinstance выше). Тестовый код требует ревью наравне с продакшн-кодом.
Проблема оракула: как вы вообще знаете, что результат верный
Самое недооценённое понятие в тестировании. Тестовый оракул — механизм, определяющий, корректен ли наблюдаемый результат. Без оракула нет теста: есть запуск.
Проблема в том, что точный оракул часто недоступен. Как проверить корректность результата поисковой выдачи? Отрендеренного PDF? Рекомендательной модели? Расчёта страховой премии по 200-страничной методике?
Виды оракулов, от самого дорогого к самому дешёвому:
Пример свойственного (property-based) оракула: мы не знаем правильный ответ для конкретного входа, но знаем инвариант, который должен выполняться для всех входов.
from hypothesis import given, strategies as st
from billing import apply_discount
@given(
price=st.floats(min_value=0, max_value=1_000_000, allow_nan=False),
percent=st.integers(min_value=-1000, max_value=1000),
)
def test_discount_invariants(price: float, percent: int) -> None:
result = apply_discount(price, percent)
# Инвариант 1: цена со скидкой не может быть отрицательной.
assert result >= 0
# Инвариант 2: скидка не может увеличить цену.
assert result <= price
# Инвариант 3: монотонность — больший процент даёт не большую цену.
if percent < 1000:
assert apply_discount(price, percent + 1) <= result + 1e-9
Мы нигде не написали «для 100 и 10 должно быть 90», но эти три инварианта поймают дефект с percent > 100 немедленно — hypothesis подберёт контрпример и сократит его до минимального.
Пример метаморфического оракула на TypeScript — проверяем не значение, а отношение между двумя запусками:
import { describe, expect, it } from "vitest";
import { search } from "./search";
describe("метаморфические отношения поиска", () => {
it("уточнение запроса не расширяет выдачу", async () => {
const broad = await search("ноутбук");
const narrow = await search("ноутбук 16 гб");
// Не знаем «правильную» выдачу, но знаем: уточнение сужает.
expect(narrow.total).toBeLessThanOrEqual(broad.total);
});
it("порядок слов не должен менять множество результатов", async () => {
const a = await search("красный шарф");
const b = await search("шарф красный");
expect(new Set(b.ids)).toEqual(new Set(a.ids));
});
});
Метаморфическое тестирование — рабочая техника для систем без точного оракула: ML-моделей, поиска, компиляторов, графики. Основополагающая работа: Chen et al., «Metamorphic Testing: A Review of Challenges and Opportunities».
Практический совет. Когда вы не можете сформулировать оракул для проверки — это сигнал. Либо требование сформулировано слишком размыто (тогда идите к аналитику: вы только что нашли дефект в требованиях), либо задача действительно требует эвристики. Фраза «работает корректно» в тест-кейсе означает, что оракула нет.
Рабочий словарь: уровни, типы, техники
Три ортогональные оси, которые постоянно путают. Уровень отвечает на вопрос «что за объект тестируем», тип — «какое свойство проверяем», техника — «как выбираем тесты».
Уровни тестирования (детализация — статьи 05–07 курса):
| Уровень | Объект | Кто обычно делает | Кто владеет окружением |
|---|---|---|---|
| Модульный (unit) | Функция, класс, модуль в изоляции | Разработчик | Никакого — всё в памяти |
| Интеграционный | Взаимодействие модулей, модуль + БД/брокер | Разработчик, реже QA | Testcontainers, docker-compose |
| Системный | Собранная система целиком | QA | Тестовый стенд |
| Приёмочный (UAT) | Система с точки зрения бизнеса | Заказчик, аналитик, QA | Пре-прод |
Типы тестирования — соответствуют характеристикам ISO 25010:
- функциональные — что система делает;
- нефункциональные — как она это делает: производительность (https://courses.digitable.life/post/testing/09-performance-testing/), безопасность (https://courses.digitable.life/post/testing/10-security-testing/), совместимость и доступность (https://courses.digitable.life/post/testing/11-mobile-and-compatibility/), удобство;
- структурные — проверка внутренней структуры, покрытие путей и ветвей;
- связанные с изменениями — подтверждающее (confirmation, он же re-test: проверяем, что конкретный баг починен) и регрессионное (проверяем, что починка ничего не сломала). Это разные вещи; в баг-трекере это разные переходы состояний.
Техники — по уровню доступа к внутренностям:
- Чёрный ящик — тесты выводятся из спецификации, без знания кода. Плюс: находят пропущенную функциональность, не наследуют заблуждения разработчика. Минус: не видят ветвей, о которых спека молчит.
- Белый ящик — тесты выводятся из структуры кода. Плюс: систематическое покрытие ветвей. Минус: не находят отсутствующий код — если фича не реализована, покрывать нечего.
- Серый ящик — знаем архитектуру и схему БД, но тестируем через внешний интерфейс. Реальный режим большинства сильных тестировщиков.
И ещё одна пара, которую путают почти все:
- Статическое тестирование — анализ артефакта без исполнения: ревью, инспекции по Фагану, линтеры, статический анализ, проверка типов. Дешевле динамического и находит другие классы дефектов — прежде всего дефекты требований и дизайна.
- Динамическое тестирование — исполнение системы.
Позитивное тестирование проверяет, что система делает то, что должна, на валидных данных. Негативное — что она корректно отказывает на невалидных. Соотношение в зрелом наборе обычно в пользу негативного: правильных сценариев мало, способов сломать — много.
Жизненный цикл дефекта
Термины про баг-трекер стоит знать точно — это язык ежедневной коммуникации.
Два состояния заслуживают внимания. Reopened — метрика здоровья процесса: высокая доля переоткрытых дефектов означает, что разработчик чинит симптом, а не причину, либо не воспроизводит баг перед фиксом. Deferred — самое опасное: это официальное решение жить с дефектом. Оно должно приниматься осознанно и человеком с полномочиями, а не молча.
Severity и Priority — не одно и то же
Классическая путаница на собеседованиях и в реальных спорах.
- Severity (серьёзность) — объективная характеристика технического воздействия: насколько сильно сломано. Определяет тестировщик.
- Priority (приоритет) — решение бизнеса о порядке починки. Определяет продакт или лид.
Все четыре комбинации реальны:
| Высокий приоритет | Низкий приоритет | |
|---|---|---|
| Высокая severity | Падает оплата в чекауте. Чиним немедленно. | Полный краш в модуле, которым пользуется один клиент раз в год через месяц. |
| Низкая severity | Опечатка в названии компании на главной странице перед пресс-конференцией. | Съехавший на 2px отступ в футере админки. |
Правый верхний угол — самая недооценённая клетка: косметический по технике дефект с огромной бизнес-ценой. Если тестировщик выставляет приоритет по severity, он теряет доверие бизнеса, а если ставит severity по приоритету — теряет технический смысл поля.
Минимальный полезный баг-репорт
Формат подробно разбирается в https://courses.digitable.life/post/testing/03-documentation/, но базовый скелет — часть терминологического минимума:
Заголовок: Скидка > 100% даёт отрицательную сумму заказа в корзине
Окружение: stage, build 2026.7.14-rc3, Chrome 138, аккаунт b2b_test_01
Шаги воспроизведения:
1. Войти под b2b_test_01.
2. Добавить в корзину товар «Кресло Nord» (12 000 ₽).
3. Применить промокод SUPER150 (номинал 150%).
4. Открыть страницу корзины.
Фактический результат: итого = −6 000 ₽; кнопка «Оплатить» активна.
Ожидаемый результат: итого = 0 ₽ (по разделу 4.2 спецификации биллинга),
либо промокод отклоняется с ошибкой.
Severity: Critical (возможна отрицательная транзакция)
Приоритет: предлагаю Highest — воспроизводится на всех промокодах > 100%
Воспроизводимость: 5/5
Приложения: har-файл, скриншот, лог billing-service (trace_id 9f2c...)
Ключевое здесь — разделение фактического и ожидаемого результата с указанием источника ожидания. Ссылка на пункт спецификации превращает спор «баг или фича» в проверяемое утверждение. Если источника ожидания нет — вы нашли дефект требований, и репорт нужно заводить именно так.
Стоимость и риск: как решать, что тестировать
Полноценный риск-ориентированный подход — тема статьи https://courses.digitable.life/post/testing/12-automation-strategy/, но базовая рамка относится к терминологии.
Риск в тестировании — сочетание двух независимых оценок: вероятности того, что дефект есть и проявится, и ущерба, если он проявится. Тестирование не устраняет риск, оно снижает неопределённость относительно него. Это важная переформулировка: тест не делает продукт лучше, он делает наше знание о продукте точнее. Улучшает продукт исправление дефекта, а не его обнаружение.
Оценка вероятности не берётся с потолка. Хорошие сигналы: частота изменений модуля (git log по файлу), сложность кода, история дефектов, число разработчиков, трогавших модуль, свежесть кода, наличие внешних интеграций.
# Быстрая эвристика: топ-15 самых изменяемых файлов за год.
# Пересечение с историей багов даёт кандидатов на глубокое тестирование.
git log --since="1 year ago" --name-only --pretty=format: \
| grep -E '\.(py|ts|go)$' \
| sort | uniq -c | sort -rn | head -15
Где расходятся взгляды. Разработчик оценивает риск через сложность кода: «здесь запутанная логика, надо покрыть». Тестировщик — через ущерб для пользователя: «здесь простой код, но если он сломается, мы потеряем деньги клиентов». Обе оценки нужны, и они не совпадают. Простейший модуль перевода денег может быть тривиальным по коду и катастрофическим по последствиям.
Мини-словарь: что часто путают
| Часто говорят | На самом деле | Почему это важно |
|---|---|---|
| «Баг» про всё подряд | Failure — то, что наблюдали; Defect — причина в коде | Иначе баг-репорт описывает симптом без данных для локализации |
| «Тест упал — значит баг» | Мог упасть тест: устаревшее ожидание, флак, проблема стенда | Ложные баги подрывают доверие к автотестам |
| «Покрытие 85% — качество высокое» | Покрытие = Reachability, не Infection и не Propagation | Метрика превращается в самообман |
| «Регресс» = «прогнать все тесты» | Регресс — проверка, что изменение не сломало работавшее | Иначе регресс раздувается и перестаёт помещаться в релизный цикл |
| «Смоук» = «быстрые тесты» | Смоук — проверка, что сборку вообще имеет смысл тестировать | Критерий отбора — не скорость, а «сломано ли принципиально» |
| «QA» = «человек, который кликает» | QA — работа с процессом; клики — QC | Иначе процесс никто не улучшает |
| «Автотест заменит ручное» | Автотест повторяет известную проверку; исследовательское находит неизвестное | Разные функции, друг друга не заменяют |
| «Приёмочные критерии» = «тест-кейсы» | Критерии — условия принятия истории; кейсы — как их проверить | Смешение приводит к историям, которые невозможно закрыть |
| «Верификация» ≈ «валидация» | Разные вопросы: соответствие спеке vs решение задачи | Продукт проходит одно и проваливает другое |
| «Severity» ≈ «Priority» | Техническое воздействие vs бизнес-очерёдность | Потеря доверия бизнеса или потеря технического смысла |
Отдельно про entry/exit criteria и Definition of Done — их путают постоянно:
- Entry criteria — условия, при которых имеет смысл начинать тестирование: сборка задеплоена, смоук зелёный, тестовые данные готовы, известны изменения. Без них команда тратит день на тестирование сломанной сборки.
- Exit criteria — условия завершения: все запланированные кейсы выполнены, нет открытых блокеров, известные дефекты приняты явным решением. Формулировка «багов нет» в качестве exit criteria недостижима — см. принцип 1.
- Definition of Done — командное соглашение о готовности любой задачи (код влит, тесты написаны, документация обновлена, ревью пройдено). DoD — инструмент QA (процесс), exit criteria — инструмент управления тестированием (конкретный цикл).
Типичные ошибки на старте
- Заводить дефект без ожидаемого результата. «Кнопка работает неправильно» — это не репорт. Ожидание должно ссылаться на источник: спека, аналог, здравый смысл (последнее нужно явно помечать).
- Путать «не воспроизводится» с «не дефект». Невоспроизводимый баг — это дефект с недостаточно исследованными условиями. Часто он самый опасный: race condition, зависимость от таймзоны, состояние кэша.
- Считать метрики целью. Число написанных кейсов, процент покрытия, количество найденных багов — все они моментально ломаются при попытке оптимизировать (закон Гудхарта). Тестировщик, которого меряют числом багов, начинает заводить косметику.
- Тестировать только позитивные сценарии. Самая частая слепота новичков и разработчиков: пишем тест на happy path и считаем функцию покрытой.
- Верить зелёному прогону без проверки самих тестов. Простой способ проверить: сломайте код намеренно и убедитесь, что тест краснеет. Это ручное мутационное тестирование за 30 секунд.
- Игнорировать статическое тестирование. Ревью требований — самая дешёвая проверка в арсенале, и её почти никто не делает системно.
Мини-итог
- Ошибка → дефект → сбой — три разные сущности. Мы наблюдаем сбои, ищем дефекты, предотвращаем ошибки.
- Чтобы тест нашёл дефект, нужны все три условия RIP. Покрытие кода отвечает только за первое — отсюда его репутация метрики-самообмана.
- Верификация сверяет продукт со спецификацией, валидация — с потребностью. Большая часть «тестирования» в командах — верификация; из-за этого продукт бывает правильно сделан и не нужен.
- Качество — вектор (ISO/IEC 25010) и всегда чья-то ценность (Вайнберг). Спор «баг или не баг» решается вопросом «для кого потеря и насколько значимая».
- Оракул — то, что отличает тест от запуска. Нет оракула — нет теста; невозможность сформулировать оракул есть дефект требований.
- Семь принципов ISTQB полезны, но два из них (стоимость раннего дефекта, невозможность исчерпывающего тестирования) требуют оговорок, а к списку стоит добавить стоимость тестирования и тот факт, что тесты — тоже код с дефектами.
- Severity ≠ Priority, QA ≠ QC, регресс ≠ прогон всего. Точность языка — не педантизм, а способ не терять деньги на недопонимании.
Источники
- Ammann P., Offutt J. Introduction to Software Testing, 2nd ed. — модель RIP, критерии покрытия, формальная база. cs.gmu.edu/~offutt/softwaretest/
- Kaner C., Bach J., Pettichord B. Lessons Learned in Software Testing — контекстно-ориентированная школа, разбор мифов. kaner.com
- Weinberg G. Quality Software Management, Vol. 1: Systems Thinking — определение качества как ценности.
- Bossavit L. The Leprechauns of Software Engineering — критический разбор «кривой стоимости дефекта». leanpub.com/leprechauns
- ISTQB Certified Tester Foundation Level Syllabus — источник семи принципов и канонической терминологии.
- ISTQB Glossary — нормативные определения, доступен на русском.
- ISO/IEC 25010:2023 — модель качества продукта.
- Hypothesis documentation — property-based тестирование на Python.
- Chen T. Y. et al. Metamorphic Testing: A Review of Challenges and Opportunities — ACM Computing Surveys.
- Martin Fowler. Test Coverage — martinfowler.com/bliki/TestCoverage.html.
Что дальше
Мы разобрали, чем оперирует тестировщик. Следующий шаг — как из бесконечного пространства возможных проверок выбрать те несколько десятков, которые действительно найдут дефекты: классы эквивалентности, граничные значения, попарные комбинации и таблицы решений.
Тест-дизайн: классы эквивалентности, границы, попарное тестирование, таблицы решений