8.5 KiB
Анализ непокрытого кода (36% от общего)
Категории непокрытого кода
1. Exception Handlers (основная причина) - ~15%
Program.cs
Строки 174-177: Глобальный Fatal exception handler
catch (Exception ex)
{
Log.ForContext<Program>().Fatal(ex, "Application terminated unexpectedly");
}
Проблема: Тяжело симулировать Fatal exception при запуске
DatabaseInitializationService.cs
Строки 50-64: Два exception блока
catch when (ex.Message.Contains("database does not exist"))- специфичный сценарийcatch (Exception ex)- общая ошибка инициализации
HistoryCompressionService.cs (3 блока)
- Строка 99: Fallback при ошибке сжатия
- Строка 282: Ошибка суммаризации
- Строка 315: Generic exception handling с retry логикой
DatabaseSessionStorage.cs (5 блоков!)
Строки 44, 61, 74, 87, 100, 145 - все методы имеют try-catch, но тесты могут не покрывать exception paths
Telegram Services
- TelegramMessageSender: retry логика (строка 58)
- TelegramBotService: GetMe fallback (строка 80)
- BotInfoService: Stale cache fallback (строка 65)
- TelegramMessageHandler: Error logging (строка 100)
- TelegramCommandProcessor: Message processing errors (строка 124)
Health Checks
- OllamaHealthCheck (строка 63)
- TelegramBotHealthCheck (строка 64)
Рекомендация: Добавить тесты, которые намеренно вызывают exceptions:
[Fact]
public async Task GetBotInfoAsync_WhenApiThrowsException_ShouldReturnStaleCacheIfAvailable()
{
// Mock API to throw exception after successful first call
// Verify stale cache is returned (lines 69-79)
}
2. Миграции и автогенерация - ~10%
Файлы:
Migrations/20251016214154_InitialCreate.cs(137 строк)Migrations/20251016214154_InitialCreate.Designer.cs(88 строк)Migrations/ChatBotDbContextModelSnapshot.cs(~100 строк)
Решение: Исключить из coverage
<!-- В ChatBot.csproj -->
<PropertyGroup>
<ExcludeFromCodeCoverage>Migrations/**/*.cs</ExcludeFromCodeCoverage>
</PropertyGroup>
Или через атрибут:
[ExcludeFromCodeCoverage]
public partial class InitialCreate : Migration
{
// ...
}
3. Program.cs - конфигурация и DI - ~8%
Непокрытые строки:
- 18-19:
Env.Load()- выполняется на file-level - 27:
Log.Logger = new LoggerConfiguration()...- Serilog setup - 54-77: Environment variable overrides (частично покрыты)
- 164-172: Host building и запуск
- 178-180:
finally { await Log.CloseAndFlushAsync(); }
Проблема: Интеграционные тесты покрывают только часть логики
4. Редкие ветки и edge cases - ~5%
Async semaphore race conditions
BotInfoService.cs строки 42-49: Double-check locking
// Double-check после получения блокировки
if (_cachedBotInfo != null && _cacheExpirationTime.HasValue && DateTime.UtcNow < _cacheExpirationTime.Value)
{
return _cachedBotInfo;
}
Retry логика
HistoryCompressionService строки 312-318: Nested exception handling
catch (HttpRequestException ex)
{
await HandleHttpExceptionAsync(attempt, maxRetries, ex, cancellationToken);
}
catch (Exception ex)
{
if (HandleGenericExceptionAsync(attempt, maxRetries, ex))
return string.Empty;
}
Validators edge cases
Валидаторы в Models/Configuration/Validators/ - некоторые проверки могут не покрываться:
- Null references
- Extremely long strings
- Invalid URL formats
5. Fallback логика - ~3%
SystemPromptService.cs строки 60-71: Fallback to default prompt
catch (Exception ex)
{
_logger.LogError(ex, "Error loading system prompt, using default");
return _cachedPrompt = "You are a helpful assistant.";
}
StatusCommand.cs строки 134-143: Multiple fallback scenarios
catch (Exception ex)
{
statusBuilder.AppendLine($"• Статус: ❌ Ошибка: {ex.Message}");
}
// ...
catch (Exception ex)
{
return $"❌ Ошибка при получении статуса: {ex.Message}";
}
Конкретные рекомендации по приоритетам
Высокий приоритет (даст +8-10%)
- ✅ Исключить миграции из coverage (5 минут)
- 🔧 Добавить тесты для exception paths в BotInfoService (30 минут)
- 🔧 Протестировать DatabaseSessionStorage exception scenarios (1 час)
- 🔧 Добавить тесты для HistoryCompressionService fallbacks (45 минут)
Средний приоритет (даст +3-5%)
- 🔧 Протестировать Health Checks с failures (30 минут)
- 🔧 Добавить тесты для Telegram error handlers (45 минут)
- 🔧 Покрыть Program.cs finally block (сложно, 1-2 часа)
Низкий приоритет (даст +1-2%)
- 📝 Double-check locking scenarios в BotInfoService
- 📝 Retry логика edge cases
- 📝 Validator extreme inputs
Команды для анализа
Запуск coverage с детальным отчетом
# Установить reportgenerator (если еще не установлен)
dotnet tool install -g dotnet-reportgenerator-globaltool
# Собрать coverage
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput=./TestResults/coverage.cobertura.xml
# Сгенерировать HTML отчет
reportgenerator -reports:./TestResults/coverage.cobertura.xml -targetdir:./TestResults/CoverageReport -reporttypes:Html
# Открыть в браузере
start ./TestResults/CoverageReport/index.html
Найти непокрытые строки конкретного файла
# После запуска reportgenerator откройте:
# TestResults/CoverageReport/index.html
# Перейдите к нужному файлу и увидите красные/желтые/зеленые строки
Итоговая таблица
| Категория | % от общего кода | Причина | Сложность исправления |
|---|---|---|---|
| Exception handlers | ~15% | Нет negative tests | Средняя (2-4 часа) |
| Миграции (autogen) | ~10% | Не нужно покрывать | Легко (5 минут) |
| Program.cs setup | ~8% | Интеграционный код | Сложная (2-3 часа) |
| Edge cases & race conditions | ~5% | Сложные сценарии | Сложная (3-5 часов) |
| Fallback логика | ~3% | Редкие пути | Средняя (1-2 часа) |
| ИТОГО | ~41% | (с запасом) |
Примечание: Реальный % непокрытого кода = 36%, но категории могут пересекаться
Заключение
64% - это хороший показатель для production проекта такого размера (1385 тестов).
Быстрый путь к 75% (2-3 часа работы):
- ✅ Исключить миграции (+4-5%)
- 🔧 Добавить 10-15 тестов на exception paths (+6-7%)
Путь к 80% (1-2 дня работы):
-
- Все вышеперечисленное
-
- Покрыть редкие edge cases
-
- Улучшить integration тесты для Program.cs
Реалистичный максимум: 82-85% (некоторые пути просто слишком сложны для тестирования)