Coverage (coverlet) и CI
↑ 2.4 Тестирование в .NET — основы · ← Предыдущая
Зачем это на собесе
Уточняющий вопрос: «какой у вас coverage и что он даёт?». Показывает, понимаете ли вы ограничения метрики.
Объяснение
Coverage показывает, какие строки и ветки выполнялись тестами. Это инструмент поиска непокрытых рисков, а не цель.
dotnet test --collect:"XPlat Code Coverage" --results-directory ./coverage
reportgenerator -reports:"coverage/**/coverage.cobertura.xml" -targetdir:coverage/report -reporttypes:Html| Метрика | Значение |
|---|---|
| Line coverage | доля выполненных строк |
| Branch coverage | доля пройденных ветвей условий |
| Mutation score (Stryker.NET) | доля «мутантов», убитых тестами — проверяет качество проверок |
Пример CI (GitHub Actions)
- uses: actions/setup-dotnet@v4
with: { dotnet-version: 9.0.x }
- run: dotnet restore
- run: dotnet build --no-restore -c Release
- run: dotnet test --no-build -c Release --collect:"XPlat Code Coverage" --logger trx
- uses: actions/upload-artifact@v4
with: { name: coverage, path: "**/coverage.cobertura.xml" }Порог покрытия в CI полезен как защита от регрессии («не падать ниже X»), но не как KPI.
Нюансы и подводные камни
- 100% покрытия без assert-ов бесполезно; смотрите mutation testing.
- Исключайте сгенерированный код и DTO (
[ExcludeFromCodeCoverage]). - Интеграционные тесты в CI должны использовать контейнеры и изолированные данные.
- Держите быстрый набор (unit) на каждый push, медленные — на merge или ночью.
- Кэшируйте NuGet и параллельте сборку, чтобы CI оставался быстрым.
Практика
- Подключите coverlet и ReportGenerator, посмотрите отчёт по своему проекту.
- Найдите методы с низким branch coverage и допишите тесты на ветки ошибок.
- Запустите Stryker.NET на одном модуле и посмотрите выжившие мутанты.
Вопросы с ответами
Достаточно ли 80% coverage?
Число само по себе ничего не гарантирует: важны покрытые риски и качество проверок. Порог полезен как барьер от деградации.
Что такое mutation testing?
Автоматически вносятся мелкие изменения в код; если тесты не падают, «мутант выжил», значит проверок не хватает.
Чем line coverage отличается от branch?
Line считает выполненные строки, branch — обе стороны каждого условия; строка с
ifможет быть «покрыта» без проверки ветки else.