7.8 KiB
Финальное исправление: SonarQube 67.4% → 86.59%
🔍 Проблема "Coverage on New Code"
SonarQube показывал: 67.4% Coverage on New Code
Причина: Миграции EF Core не исключались из расчета coverage
✅ Окончательное решение
1. Добавлен [ExcludeFromCodeCoverage] в файлы миграций
ChatBot/Migrations/20251016214154_InitialCreate.cs
using System.Diagnostics.CodeAnalysis;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace ChatBot.Migrations
{
[ExcludeFromCodeCoverage] // ← Добавлено
public partial class InitialCreate : Migration
{
// ...
}
}
ChatBot/Migrations/ChatBotDbContextModelSnapshot.cs
using System.Diagnostics.CodeAnalysis;
using ChatBot.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace ChatBot.Migrations
{
[DbContext(typeof(ChatBotDbContext))]
[ExcludeFromCodeCoverage] // ← Добавлено
partial class ChatBotDbContextModelSnapshot : ModelSnapshot
{
// ...
}
}
Важно: Для partial классов атрибут добавляется только в ОДИН файл!
2. Улучшены параметры SonarQube в CI/CD
.gitea/workflows/build.yml
~/.sonar/scanner/dotnet-sonarscanner begin \
/k:"mrleo1nid_chatbot" \
/o:"mrleo1nid" \
/d:sonar.token="${{ secrets.SONAR_TOKEN }}" \
/d:sonar.cs.opencover.reportsPaths="**/coverage.opencover.xml" \
/d:sonar.coverage.exclusions="**/Migrations/**/*.cs,**/*ModelSnapshot.cs,**/Migrations/*.cs,**/Program.cs" \
/d:sonar.exclusions="**/Migrations/**/*.cs,**/obj/**,**/bin/**,**/TestResults/**" \
/d:sonar.cpd.exclusions="**/Migrations/**/*.cs" \
/d:sonar.sources="." \
/d:sonar.tests="." \
/d:sonar.test.inclusions="**/*Tests.cs,**/ChatBot.Tests/**/*.cs"
Ключевые изменения:
- ✅
sonar.coverage.exclusions- более точные glob паттерны для миграций - ✅
sonar.cpd.exclusions- исключение из duplicate code detection - ✅
sonar.test.inclusions- явное указание тестовых файлов
3. Coverlet настроен для исключения миграций
dotnet test \
/p:CollectCoverage=true \
/p:CoverletOutputFormat=opencover \
/p:CoverletOutput=./coverage/ \
/p:Exclude="[*]*.Migrations.*" \
/p:ExcludeByFile="**/Migrations/*.cs"
📊 Локальные результаты (подтверждено)
========================================
COVERAGE RESULTS:
========================================
Line Coverage: 86.59% (2022 / 2335) ✅
Branch Coverage: 76.01% ✅
Tests: 1393/1393 passed ✅
========================================
🚀 Что делать дальше
Commit и push всех изменений:
# Добавить все изменения
git add .gitea/workflows/build.yml
git add ChatBot/Migrations/20251016214154_InitialCreate.cs
git add ChatBot/Migrations/20251016214154_InitialCreate.Designer.cs
git add ChatBot/Migrations/ChatBotDbContextModelSnapshot.cs
git add ChatBot.Tests/ChatBot.Tests.csproj
git add run-coverage-detailed.ps1
git add .sonarqube/exclusions.txt
# Commit
git commit -m "Fix SonarQube coverage: add [ExcludeFromCodeCoverage] to migrations, improve exclusion patterns"
# Push
git push origin master
📈 Ожидаемый результат в SonarQube
До:
❌ 67.4% Coverage on New Code
Required: 80.0%
FAILED
После (ожидается):
✅ 86.59% Coverage on New Code
Required: 80.0%
PASSED 🎉
🎯 Почему это работает
Комбинация трех методов исключения:
-
[ExcludeFromCodeCoverage]- атрибут C#- Coverlet видит атрибут и пропускает эти классы
- Самый надежный способ
-
/p:ExcludeByFile="**/Migrations/*.cs"- параметр Coverlet- Исключает файлы по паттерну
- Backup на случай, если атрибут не сработает
-
/d:sonar.coverage.exclusions- параметр SonarQube- SonarQube дополнительно исключает эти файлы
- Двойная защита
⚠️ Важные замечания
1. Partial Classes и атрибуты
Для partial классов [ExcludeFromCodeCoverage] применяется только к ОДНОЙ части:
// InitialCreate.cs
[ExcludeFromCodeCoverage] // ✅ Добавить здесь
public partial class InitialCreate : Migration
// InitialCreate.Designer.cs
partial class InitialCreate // ❌ НЕ добавлять здесь (дублирование)
2. "Coverage on New Code" vs "Overall Coverage"
- Overall Coverage: покрытие всего проекта
- Coverage on New Code: покрытие только новых изменений в текущей ветке
SonarQube может показывать разные значения для этих метрик. После merge в master оба значения станут одинаковыми.
3. Автоматическая регенерация миграций
Если вы создадите новые миграции через dotnet ef migrations add, не забудьте:
- Добавить
using System.Diagnostics.CodeAnalysis; - Добавить
[ExcludeFromCodeCoverage]к классу миграции - Добавить
[ExcludeFromCodeCoverage]к ModelSnapshot (если изменился)
🔍 Проверка перед push
Локальный тест:
.\run-coverage-detailed.ps1
Ожидаемый output:
Line Coverage: 86.59%
Branch Coverage: 76.01%
🎉 Excellent coverage (80%+)
Если видите 86.59% - значит все настроено правильно! ✅
📝 Файлы, которые были изменены
Основные изменения:
- ✅
.gitea/workflows/build.yml- улучшены параметры SonarQube - ✅
ChatBot/Migrations/*.cs- добавлен[ExcludeFromCodeCoverage] - ✅
ChatBot.Tests/ChatBot.Tests.csproj- добавлен coverlet.msbuild - ✅
run-coverage-detailed.ps1- скрипт для проверки coverage - ✅
.sonarqube/exclusions.txt- документация по исключениям
Удалены:
- ❌
sonar-project.properties- не используется SonarScanner for .NET
🎉 Итоговая статистика
| Метрика | Значение | Статус |
|---|---|---|
| Line Coverage | 86.59% | ✅ Выше 80% |
| Branch Coverage | 76.01% | ✅ Приемлемо |
| Всего тестов | 1393 | ✅ Все проходят |
| Новые тесты | +8 | ✅ Добавлены |
| SonarQube Quality Gate | PASSED (ожидается) | ✅ |
🏆 Результат
Проблема полностью решена!
Комбинация [ExcludeFromCodeCoverage] атрибутов + улучшенных glob паттернов в SonarQube + правильной конфигурации coverlet обеспечивает:
- ✅ 86.59% coverage локально
- ✅ ~86-87% coverage в SonarQube (ожидается)
- ✅ Проходит Quality Gate (требование 80%)
- ✅ Миграции полностью исключены из расчета
Готово к push! 🚀