Опишите принципы тестирования ПО: юнит-тесты, интеграционные тесты, e2e, property-based testing — как подобрать набор тестов для критического модуля и какие метрики качества тестового покрытия имеют практический смысл
Кратко и по делу. Что такое и зачем - Unit-тесты — проверяют отдельные функции/классы в изоляции (моки для зависимостей). Быстрые, детальные, хороши для охвата логики и граничных случаев. - Интеграционные тесты — проверяют взаимодействие между компонентами (базы данных, сети, очередь). Медленнее, ловят ошибки интерфейсов и конфигураций. - E2E (end-to-end) — проверяют полный бизнес‑путь системы от входа до выхода в условиях, близких к проду. Дорогие и медленные, но важны для пользовательской корректности. - Property-based testing — формулируете инварианты/свойства системы и генерируете много входных данных; помогает находить редкие ошибки и доказать общие свойства (например, обратимость, идемпотентность, сохранение инвариантов). Как подобрать набор тестов для критического модуля 1. Анализ риска и требований - Выделить критичные сценарии (безопасность, деньги, доступность), требования и последствия отказа. 2. Модель покрытия тестов (пирамида) - Много unit-тестов для логики, несколько интеграционных для интерфейсов и небольшое число e2e для пользовательских сценариев. 3. Что тестировать в unit: - Все ветвления и граничные случаи, ошибки ввода, исключения, математические/логические операции. 4. Что тестировать в интеграции: - Контракты API, миграции схем, сериализация, таймауты, ретраи, транзакции, согласованность данных между сервисами. 5. Что тестировать в e2e: - Основные пользов. сценарии (happy path), критичные отказные сценарии, rollback/приёма-завершения операций. 6. Property-based и fuzzing: - Для сложных трансформаций данных, парсеров, сериализаторов, криптографии и т. п. — формулируете свойства и генерируете входы. 7. Негативное/имитационное тестирование: - Fault-injection, нехватка ресурсов, сетевые сбои, нагрузочные тесты для критичных SLA. 8. Автоматизация и приоритизация - Быстрые unit-тесты в PR; интеграционные и часть property/fuzz — в nightly; e2e — в релизной ветке или canary. Практичные метрики покрытия (и как их использовать) - Statement coverage (инструкции) — доля исполненных строк: StmtCov=ExecutedStatementsTotalStatements\text{StmtCov} = \frac{\text{ExecutedStatements}}{\text{TotalStatements}}StmtCov=TotalStatementsExecutedStatements. Полезна, но легко обмануть. - Branch coverage — доля покрытых ветвлений (if/else): BranchCov=CoveredBranchesTotalBranches\text{BranchCov} = \frac{\text{CoveredBranches}}{\text{TotalBranches}}BranchCov=TotalBranchesCoveredBranches. Значимее, т.к. учитывает условия. - Function/Method coverage — доля вызванных функций. - Cyclomatic complexity — даёт нижнюю границу числа независимых путей и помогает планировать тесты: V(G)=E−N+2P\mathrm{V}(G)=E-N+2PV(G)=E−N+2P (часто P=1P=1P=1). Чем выше V, тем больше тестов нужно. - Mutation score — лучший признак качества тестов: MutationScore=KilledMutantsTotalMutants\text{MutationScore}=\frac{\text{KilledMutants}}{\text{TotalMutants}}MutationScore=TotalMutantsKilledMutants. Показывает, ловят ли тесты реальные ошибки. - Requirements/test-case coverage — соотнесение тестов с требованиями/критичными сценариями (важно для критических модулей). - Практические оперметрики: время выполнения тестов, частота флаков (flaky rate), среднее время на обнаружение регрессии. Руководящие числа (ориентиры, не догма) - Unit/branch coverage цель: > 80%\mathbf{80\%}80%–90%\mathbf{90\%}90% для критичных модулей, но не гоняться за 100%100\%100%. - Mutation score целевой минимум: около 60%\mathbf{60\%}60%–80%\mathbf{80\%}80% для уверенности в тестах. - Cyclomatic complexity: делайте рефакторинг, если V(G)>10\mathrm{V}(G) > \mathbf{10}V(G)>10–15\mathbf{15}15. - Flaky rate стремитесь к 0%\mathbf{0\%}0%; всё, что заметно выше — приоритет фиксить. Практические советы - Не заменяйте здравый смысл метриками: высокая покрытие =/= отсутствие багов. - Ставьте тесты на контракт/инварианты, а не на конкретные реализации. - Используйте mutation + PBT + фазы тестирования (PR/CI/nightly/release) для баланса скорости и глубины. - Введите мониторинг тестовой эффективности: сколько багов клиенты находят в покрытых местах, среднее время на фиксацию регрессии. Коротко: unit — для логики и быстрых проверок; интеграция — для контрактов; e2e — для ключевых бизнес‑сценариев; property-based/fuzzing — для больших/непредсказуемых входных пространств. Используйте branch/mutation/requirements coverage и сложность как практические ориентиры, но фокусируйтесь на рисках и свойствах, а не на погоне за процентами.
Что такое и зачем
- Unit-тесты — проверяют отдельные функции/классы в изоляции (моки для зависимостей). Быстрые, детальные, хороши для охвата логики и граничных случаев.
- Интеграционные тесты — проверяют взаимодействие между компонентами (базы данных, сети, очередь). Медленнее, ловят ошибки интерфейсов и конфигураций.
- E2E (end-to-end) — проверяют полный бизнес‑путь системы от входа до выхода в условиях, близких к проду. Дорогие и медленные, но важны для пользовательской корректности.
- Property-based testing — формулируете инварианты/свойства системы и генерируете много входных данных; помогает находить редкие ошибки и доказать общие свойства (например, обратимость, идемпотентность, сохранение инвариантов).
Как подобрать набор тестов для критического модуля
1. Анализ риска и требований
- Выделить критичные сценарии (безопасность, деньги, доступность), требования и последствия отказа.
2. Модель покрытия тестов (пирамида)
- Много unit-тестов для логики, несколько интеграционных для интерфейсов и небольшое число e2e для пользовательских сценариев.
3. Что тестировать в unit:
- Все ветвления и граничные случаи, ошибки ввода, исключения, математические/логические операции.
4. Что тестировать в интеграции:
- Контракты API, миграции схем, сериализация, таймауты, ретраи, транзакции, согласованность данных между сервисами.
5. Что тестировать в e2e:
- Основные пользов. сценарии (happy path), критичные отказные сценарии, rollback/приёма-завершения операций.
6. Property-based и fuzzing:
- Для сложных трансформаций данных, парсеров, сериализаторов, криптографии и т. п. — формулируете свойства и генерируете входы.
7. Негативное/имитационное тестирование:
- Fault-injection, нехватка ресурсов, сетевые сбои, нагрузочные тесты для критичных SLA.
8. Автоматизация и приоритизация
- Быстрые unit-тесты в PR; интеграционные и часть property/fuzz — в nightly; e2e — в релизной ветке или canary.
Практичные метрики покрытия (и как их использовать)
- Statement coverage (инструкции) — доля исполненных строк: StmtCov=ExecutedStatementsTotalStatements\text{StmtCov} = \frac{\text{ExecutedStatements}}{\text{TotalStatements}}StmtCov=TotalStatementsExecutedStatements . Полезна, но легко обмануть.
- Branch coverage — доля покрытых ветвлений (if/else): BranchCov=CoveredBranchesTotalBranches\text{BranchCov} = \frac{\text{CoveredBranches}}{\text{TotalBranches}}BranchCov=TotalBranchesCoveredBranches . Значимее, т.к. учитывает условия.
- Function/Method coverage — доля вызванных функций.
- Cyclomatic complexity — даёт нижнюю границу числа независимых путей и помогает планировать тесты: V(G)=E−N+2P\mathrm{V}(G)=E-N+2PV(G)=E−N+2P (часто P=1P=1P=1). Чем выше V, тем больше тестов нужно.
- Mutation score — лучший признак качества тестов: MutationScore=KilledMutantsTotalMutants\text{MutationScore}=\frac{\text{KilledMutants}}{\text{TotalMutants}}MutationScore=TotalMutantsKilledMutants . Показывает, ловят ли тесты реальные ошибки.
- Requirements/test-case coverage — соотнесение тестов с требованиями/критичными сценариями (важно для критических модулей).
- Практические оперметрики: время выполнения тестов, частота флаков (flaky rate), среднее время на обнаружение регрессии.
Руководящие числа (ориентиры, не догма)
- Unit/branch coverage цель: > 80%\mathbf{80\%}80%–90%\mathbf{90\%}90% для критичных модулей, но не гоняться за 100%100\%100%.
- Mutation score целевой минимум: около 60%\mathbf{60\%}60%–80%\mathbf{80\%}80% для уверенности в тестах.
- Cyclomatic complexity: делайте рефакторинг, если V(G)>10\mathrm{V}(G) > \mathbf{10}V(G)>10–15\mathbf{15}15.
- Flaky rate стремитесь к 0%\mathbf{0\%}0%; всё, что заметно выше — приоритет фиксить.
Практические советы
- Не заменяйте здравый смысл метриками: высокая покрытие =/= отсутствие багов.
- Ставьте тесты на контракт/инварианты, а не на конкретные реализации.
- Используйте mutation + PBT + фазы тестирования (PR/CI/nightly/release) для баланса скорости и глубины.
- Введите мониторинг тестовой эффективности: сколько багов клиенты находят в покрытых местах, среднее время на фиксацию регрессии.
Коротко: unit — для логики и быстрых проверок; интеграция — для контрактов; e2e — для ключевых бизнес‑сценариев; property-based/fuzzing — для больших/непредсказуемых входных пространств. Используйте branch/mutation/requirements coverage и сложность как практические ориентиры, но фокусируйтесь на рисках и свойствах, а не на погоне за процентами.