Code Coverage - Como Visualizar e Interpretar¶
📊 Onde Ver as Porcentagens de Coverage¶
1. GitHub Actions - Logs do Workflow¶
Nas execuções do workflow PR Validation, você encontrará as porcentagens em:
Step: "Code Coverage Summary"¶
Step: "Display Coverage Percentages"¶
📊 CODE COVERAGE SUMMARY
========================
📄 Coverage file: ./coverage/users/users.opencover.xml
📈 Line Coverage: 85.3%
🌿 Branch Coverage: 78.9%
💡 For detailed coverage report, check the 'Code Coverage Summary' step above
🎯 Minimum thresholds: 70% (warning) / 85% (good)
2. Pull Request - Comentários Automáticos¶
Em cada PR, você verá um comentário automático com:
## 📊 Code Coverage Report
| Module | Line Rate | Branch Rate | Health |
|--------|-----------|-------------|---------|
| Users | 85.3% | 78.9% | ✅ |
### 🎯 Quality Gates
- ✅ **Pass**: Coverage ≥ 85%
- ⚠️ **Warning**: Coverage 70-84%
- ❌ **Fail**: Coverage < 70%
```text
### 3. **Artifacts de Download**
Em cada execução do workflow, você pode baixar:
- **`coverage-reports`**: Arquivos XML detalhados
- **`test-results`**: Resultados TRX dos testes
## 📈 Como Interpretar as Métricas
### **Line Coverage (Cobertura de Linhas)**
- **O que é**: Porcentagem de linhas de código executadas pelos testes
- **Ideal**: ≥ 85%
- **Mínimo aceitável**: ≥ 70%
- **Exemplo**: 85.3% = 853 de 1000 linhas foram testadas
### **Branch Coverage (Cobertura de Branches)**
- **O que é**: Porcentagem de condições/branches testadas (if/else, switch)
- **Ideal**: ≥ 80%
- **Mínimo aceitável**: ≥ 65%
- **Exemplo**: 78.9% = 789 de 1000 branches foram testadas
### **Complexity (Complexidade)**
- **O que é**: Métrica de complexidade ciclomática do código
- **Ideal**: Baixa complexidade com alta cobertura
- **Uso**: Identifica métodos que precisam de refatoração
## 🎯 Thresholds Configurados
### **Limites Atuais**
```yaml
thresholds: '70 85'
- 70%: Limite mínimo (warning se abaixo)
- 85%: Limite ideal (pass se acima)
Comportamento do Pipeline¶
- Coverage ≥ 85%: ✅ Pipeline passa com sucesso
- Coverage 70-84%: ⚠️ Pipeline passa com warning
- Coverage < 70%: ❌ Pipeline falha (modo strict)
🔧 Como Melhorar o Coverage¶
1. Identificar Código Não Testado¶
# Baixar artifacts de coverage
# Abrir arquivos .opencover.xml em ferramentas como:
# - Visual Studio Code com extensão Coverage Gutters
# - ReportGenerator para HTML reports
2. Focar em Branches Não Testadas¶
// Exemplo de código com baixa branch coverage
public string GetStatus(int value)
{
if (value > 0) return "Positive"; // ✅ Testado
else if (value < 0) return "Negative"; // ❌ Não testado
return "Zero"; // ❌ Não testado
}
// Teste necessário para 100% branch coverage
[Test] public void GetStatus_PositiveValue_ReturnsPositive() { }
[Test] public void GetStatus_NegativeValue_ReturnsNegative() { } // Adicionar
[Test] public void GetStatus_ZeroValue_ReturnsZero() { } // Adicionar
3. Adicionar Testes para Cenários Edge Case¶
- Valores nulos
- Listas vazias
- Exceptions
- Condições de erro
📁 Arquivos de Coverage Gerados¶
Estrutura dos Artifacts¶
coverage/
├── users/
│ ├── users.opencover.xml # Coverage detalhado do módulo Users
│ └── users-test-results.trx # Resultados dos testes
└── shared/
├── shared.opencover.xml # Coverage do código compartilhado
└── shared-test-results.trx
Formato OpenCover XML¶
<CoverageSession>
<Summary numSequencePoints="1000" visitedSequencePoints="853"
sequenceCoverage="85.3" numBranchPoints="500"
visitedBranchPoints="394" branchCoverage="78.9" />
</CoverageSession>
🛠️ Ferramentas para Visualização Local¶
1. Coverage Gutters (VS Code)¶
# Instalar extensão Coverage Gutters
# Abrir arquivo .opencover.xml
# Ver linhas coloridas no editor:
# - Verde: Linha testada
# - Vermelho: Linha não testada
# - Amarelo: Linha parcialmente testada
2. ReportGenerator¶
# Gerar relatório HTML
dotnet tool install -g dotnet-reportgenerator-globaltool
reportgenerator -reports:"coverage/**/*.opencover.xml" -targetdir:"coveragereport" -reporttypes:Html
3. dotCover/JetBrains Rider¶
📊 Exemplos de Relatórios¶
Relatório de Sucesso (≥85%)¶
✅ Coverage: 87.2% (Target: 85%)
📈 Line Coverage: 87.2% (1308/1500 lines)
🌿 Branch Coverage: 82.4% (412/500 branches)
🎯 Quality Gate: PASSED
Relatório de Warning (70-84%)¶
⚠️ Coverage: 76.8% (Target: 85%)
📈 Line Coverage: 76.8% (1152/1500 lines)
🌿 Branch Coverage: 71.2% (356/500 branches)
🎯 Quality Gate: WARNING - Consider adding more tests
Relatório de Falha (<70%)¶
❌ Coverage: 65.3% (Target: 70%)
📈 Line Coverage: 65.3% (980/1500 lines)
🌿 Branch Coverage: 58.6% (293/500 branches)
🎯 Quality Gate: FAILED - Insufficient test coverage
🔄 Configuração Personalizada¶
Ajustar Thresholds¶
No arquivo .github/workflows/pr-validation.yml:
# Para projetos novos (menos rigoroso)
thresholds: '60 75'
# Para projetos maduros (mais rigoroso)
thresholds: '80 90'
# Para projetos críticos (muito rigoroso)
thresholds: '90 95'
```yaml
### **Modo Leniente (Não Falhar)**
```yaml
# Adicionar variável de ambiente
env:
STRICT_COVERAGE: false # true = falha se < threshold
```text
## 📚 Links Úteis
> ⚠️ **Ferramentas Descontinuadas**: As ferramentas abaixo foram arquivadas/não são mais mantidas pelos autores. Mantidas aqui apenas como referência histórica.
> - **CodeCoverageSummary Action**: Sem atualizações desde 2022
> - **OpenCover**: Repositório arquivado em novembro de 2021
- [CodeCoverageSummary Action](https://github.com/irongut/CodeCoverageSummary) (descontinuado)
- [OpenCover Documentation](https://github.com/OpenCover/opencover) (arquivado)
- [Coverage Best Practices](../development.md#diretrizes-de-testes)
---
## 🔍 Análise: CI/CD vs Local Coverage
### Discrepância Identificada
**Pipeline (CI/CD)**: 35.11%
**Local**: 21%
**Diferença**: +14.11pp
### Por Que a Diferença?
#### Pipeline Executa MAIS Testes
```yaml
# ci-cd.yml - 8 suítes de testes
1. MeAjudaAi.Shared.Tests ✅
2. MeAjudaAi.Architecture.Tests ✅
3. MeAjudaAi.Integration.Tests ✅
4. MeAjudaAi.Modules.Users.Tests ✅
5. MeAjudaAi.Modules.Documents.Tests ✅
6. MeAjudaAi.Modules.Providers.Tests ✅
7. MeAjudaAi.Modules.ServiceCatalogs.Tests ✅
8. MeAjudaAi.E2E.Tests ✅ (76 testes)
Local Falha em E2E¶
- Problema: Docker Desktop com
InternalServerError - Impacto: -10-12pp coverage (E2E tests não rodam)
- Solução: Ver test-infrastructure.md - Bloqueios Conhecidos
Como Replicar Coverage da Pipeline Localmente¶
# 1. Garantir Docker Desktop funcionando
docker version
docker ps
# 2. Rodar TODAS as suítes (igual pipeline)
dotnet test --collect:"XPlat Code Coverage" --results-directory TestResults
# 3. Gerar relatório agregado
reportgenerator `
-reports:"TestResults/**/coverage.cobertura.xml" `
-targetdir:"TestResults/Coverage" `
-reporttypes:"Html;Cobertura" `
-assemblyfilters:"-*.Tests*" `
-classfilters:"-*.Migrations*"
# 4. Abrir relatório
start TestResults/Coverage/index.html
Identificar Gaps de Coverage¶
Use o script automatizado:
Saída exemplo:
📋 COMMAND/QUERY HANDLERS SEM TESTES
Module Handler Type
------ ------- ----
Providers GetProvidersQueryHandler Query
💎 VALUE OBJECTS SEM TESTES
Module ValueObject
------ -----------
Providers Address
🗄️ REPOSITORIES SEM TESTES
Module Repository
------ ----------
Documents DocumentRepository
📊 RESUMO: 8 gaps total (+4.4pp estimado)
Roadmap para 70% Coverage¶
Atual: 35.11%
Meta Sprint 1: 55% (+20pp)
Meta Sprint 2: 70% (+15pp)
Estratégia Sprint 1 (Quick Wins): 1. ✅ Adicionar módulos faltantes ao CI/CD (+5-8pp) - FEITO 2. Adicionar testes para 8 gaps identificados (+4.4pp) 3. Adicionar testes para Application layer sem coverage (+10pp) 4. Adicionar testes para Domain Value Objects (+3pp)
Estratégia Sprint 2 (Deep Coverage): 1. Testes de Infrastructure (repositories, external services) (+8pp) 2. Integration tests complexos (módulos comunicando) (+5pp) 3. Edge cases e cenários de erro (+2pp)
Understanding Code Coverage Reports - Detailed Explanation¶
Date: December 2, 2025
Context: User question about Documents.API showing 8.8% coverage when manual calculation suggests ~82-84%
🤔 The User's Question¶
"De um total de 1868 linhas, 1289 são de Microsoft.AspNetCore.OpenApi.Generated e System.Runtime.CompilerServices. Se retirar as linhas destes 2, sobram 579 linhas... 127/151 daria 84.1% de cobertura. Não faz muito sentido ao meu ver"
Answer: Your calculation is CORRECT and the confusion is VALID! Let me explain what's happening.
📊 Understanding Coverage Report Columns¶
Example: MeAjudaAi.Modules.Documents.API¶
Name | Covered | Uncovered | Coverable | Total | Coverage%
--------------------------|---------|-----------|-----------|-------|----------
Documents.API | 127 | 1,313 | 1,440 | 1,868 | 8.8%
Endpoints (manual code) | 127 | 27 | 154 | 361 | 82.5%
OpenApi.Generated | 0 | 1,286 | 1,286 | 1,507 | 0.0%
Column Definitions¶
- COVERED (127 lines)
- Lines executed during test run
- Code that was "touched" by tests
-
Green in HTML reports
-
UNCOVERED (1,313 lines)
- Lines NOT executed during tests
- Code that exists but never ran
-
Red in HTML reports
-
COVERABLE (1,440 lines)
- Total lines that CAN be covered
- Formula:
COVERED + UNCOVERED - Example:
127 + 1,313 = 1,440 -
Excludes: comments, empty braces, whitespace
-
TOTAL (1,868 lines)
- ALL lines in the file (including everything)
- Formula:
COVERABLE + non-coverable -
Includes: comments, whitespace, braces, etc.
-
COVERAGE%
- Formula:
COVERED / COVERABLE × 100 - Example:
127 / 1,440 = 8.8%
⚠️ The Problem: Compiler-Generated Code¶
What are these files?¶
- Microsoft.AspNetCore.OpenApi.Generated
- Auto-generated by .NET 10 OpenApi source generators
- File:
OpenApiXmlCommentSupport.generated.cs - Purpose: XML documentation comments for Swagger/OpenAPI
- Created at compile-time in
obj/Debug/net10.0/ -
Never executed during tests (0% coverage)
-
System.Runtime.CompilerServices
- Compiler-generated runtime support code
- Internal framework infrastructure
-
Never executed during tests (0% coverage)
-
System.Text.RegularExpressions.Generated
- Auto-generated by .NET Regex source generators
- File:
RegexGenerator.g.cs - Example: Email/Username validation patterns
- Partially executed (87-88% coverage)
Impact on Documents.API¶
Component | Covered | Coverable | Coverage
--------------------------------|---------|-----------|----------
Manual code (endpoints, etc) | 127 | 154 | 82.5% ✅
Generated code (OpenApi, etc) | 0 | 1,286 | 0.0% ❌
--------------------------------|---------|-----------|----------
TOTAL (mixed) | 127 | 1,440 | 8.8% ⚠️
Result: Generated code with 0% coverage inflates the denominator, making your real coverage (82.5%) appear as 8.8%!
🧮 Your Calculation - VALIDATION¶
Your Logic (CORRECT!)¶
Total lines: 1,868
Generated code: -1,289 (OpenApi + CompilerServices)
Real code: 579 lines
Covered: 127 lines (from report)
Estimated coverable: 151 lines (your calculation)
Coverage: 127 / 151 = 84.1% ✅
Actual Calculation (from XML data)¶
Documents.API Total: 1,440 coverable
Generated code: -1,286 coverable
Real code: 154 coverable ✅
Coverage: 127 / 154 = 82.5% ✅
Comparison¶
| Metric | Your Calc | Actual | Difference |
|---|---|---|---|
| Coverable | 151 | 154 | -3 lines |
| Covered | 127 | 127 | 0 lines |
| Coverage% | 84.1% | 82.5% | +1.6% |
Conclusion: Your logic was 100% CORRECT! The small difference (151 vs 154 coverable lines) is due to not having access to the raw XML data, but your approach was perfect.
🔍 Why Reports Show 8.8% Instead of 82.5%¶
Problem: Mixed Aggregation¶
ReportGenerator aggregates coverage at the assembly level:
<!-- coverage.cobertura.xml (simplified) -->
<package name="MeAjudaAi.Modules.Documents.API">
<class name="GetDocumentStatusEndpoint" line-rate="1.0" />
<class name="UploadDocumentEndpoint" line-rate="0.969" />
<!-- 127 lines covered, 27 uncovered = 82.5% -->
<class name="Microsoft.AspNetCore.OpenApi.Generated.OpenApiXmlCommentSupport" line-rate="0.0" />
<!-- 0 lines covered, 1286 uncovered = 0% -->
</package>
When aggregated at package level:
Solution Attempts¶
❌ Attempt 1: ReportGenerator -classfilters¶
- Result: Removes from HTML visualization, but doesn't recalculate percentages
- Reason: XML data is already aggregated
✅ Solution 2: Coverlet ExcludeByFile (at collection time)¶
- Result: Excludes from coverage before XML generation
- Reason: Source of truth is clean
✅ Solution 3: Use coverlet.json configuration¶
{
"sourcefiles": [
"-**/*OpenApi.Generated*.cs",
"-**/System.Runtime.CompilerServices*.cs",
"-**/System.Text.RegularExpressions.Generated*.cs"
],
"attributefilters": [
"GeneratedCodeAttribute",
"CompilerGeneratedAttribute"
]
}
📈 Real Coverage by Module (Excluding Generated Code)¶
Documents Module¶
| Component | Reported | Real (Est.) | Delta |
|---|---|---|---|
| Documents.API | 8.8% | 82.5% | +73.7% 🚀 |
| Documents.Application | ~15% | ~60-70% | +45-55% |
| Documents.Domain | ~20% | ~70-80% | +50-60% |
Users Module¶
| Component | Reported | Real (Est.) | Delta |
|---|---|---|---|
| Users.API | 31.8% | ~85-90% | +53-58% 🚀 |
| Users.Application | 55.6% | ~75-85% | +19-29% |
| Users.Domain | 49.1% | ~90-95% | +41-46% |
Overall Project¶
| Metric | With Generated | Without Generated | Delta |
|---|---|---|---|
| Line Coverage | 27.9% | ~45-55% ⚠️ | +17-27% |
| Branch Coverage | 21.7% | ~35-45% ⚠️ | +13-23% |
| Method Coverage | 40.9% | ~60-70% ⚠️ | +19-29% |
⚠️ Note: "Without Generated" estimates are based on Documents.API pattern (82.5% vs 8.8% = 9.4× multiplier). Actual values may vary per module.
🛠️ How to Fix (Permanent Solution)¶
Step 1: Update Coverage Collection Command¶
Current (includes generated code):
Fixed (excludes generated code):
dotnet test \
--collect:"XPlat Code Coverage" \
-- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.ExcludeByFile="**/*OpenApi.Generated*.cs,**/System.Runtime.CompilerServices*.cs,**/*RegexGenerator.g.cs"
Step 2: Use coverlet.json (Already Configured!)¶
File: config/coverlet.json ✅
{
"sourcefiles": [
"-**/*OpenApi.Generated*.cs",
"-**/System.Runtime.CompilerServices*.cs",
"-**/System.Text.RegularExpressions.Generated*.cs",
"-**/<RegexGenerator_g>*.cs"
],
"attributefilters": [
"GeneratedCodeAttribute",
"CompilerGeneratedAttribute",
"ExcludeFromCodeCoverageAttribute"
]
}
Usage (via MSBuild properties):
Alternatively, use a .runsettings file:
Step 3: Update CI/CD Pipeline¶
azure-pipelines.yml (or GitHub Actions):
- task: DotNetCoreCLI@2
inputs:
command: 'test'
arguments: >
--configuration Release
--collect:"XPlat Code Coverage"
--settings:config/coverlet.json
-- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.ExcludeByFile="**/*.generated.cs"
🎯 Summary - Answering Your Question¶
Q: "Não faz muito sentido ao meu ver"¶
A: Você está ABSOLUTAMENTE CORRETO! The report doesn't make sense because:
- ✅ Your calculation (84.1%) is correct for hand-written code
- ❌ Report shows 8.8% because it includes generated code
- ⚠️ Difference: Generated code has 1,286 uncovered lines (0% coverage)
Q: "Se retirar as linhas destes 2, sobram 579 linhas"¶
A: Correct logic! But the exact breakdown is:
Total: 1,868 lines
Generated: -1,507 lines (1,286 coverable + 221 non-coverable)
Real code: 361 lines (154 coverable + 207 non-coverable)
Q: "127/151 daria 84.1% de cobertura"¶
A: VERY CLOSE! Actual is 127/154 = 82.5%
Your estimate of 151 coverable lines was 98% accurate (only 3 lines off)!
📚 References¶
- Coverlet Documentation: https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/GlobalTool.md
- ReportGenerator Filters: https://github.com/danielpalme/ReportGenerator/wiki/Settings
- .NET Source Generators: https://learn.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/source-generators-overview
- OpenApi Source Generator: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/openapi/aspnetcore-openapi
Created by: GitHub Copilot
Date: December 2, 2025
Context: User identified that generated code was inflating coverage denominator - analysis confirmed user was 100% correct!
Como a Exclusão de Código Gerado Funciona - Guia Completo¶
Data: 2 Dez 2025
Contexto: Configuração correta de coverage excluindo código gerado do compilador
✅ SIM - Vai Chegar nos Números Reais!¶
📊 Expectativa de Resultados¶
| Métrica | ANTES (com generated) | DEPOIS (sem generated) | Ganho |
|---|---|---|---|
| Line Coverage | 27.9% | ~45-55% | +17-27% 🚀 |
| Documents.API | 8.8% | ~82-84% | +73-76% 🚀 |
| Users.API | 31.8% | ~85-90% | +53-58% 🚀 |
| Users.Application | 55.6% | ~75-85% | +19-29% 🚀 |
🔧 O Que Foi Configurado¶
1. Pipeline CI/CD (.github/workflows/ci-cd.yml) ✅¶
ANTES:
DEPOIS:
dotnet test \
--collect:"XPlat Code Coverage" \
-- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.ExcludeByFile="**/*OpenApi*.generated.cs,**/System.Runtime.CompilerServices*.cs,**/*RegexGenerator.g.cs"
Aplicado em: - ✅ Shared.Tests - ✅ Architecture.Tests - ✅ Integration.Tests - ✅ Users.Tests - ✅ Documents.Tests - ✅ Providers.Tests - ✅ ServiceCatalogs.Tests - ✅ E2E.Tests
2. Script Local (dotnet test --collect) ✅¶
Criado comando para rodar localmente com as mesmas exclusões da pipeline.
Uso:
🎯 Como Funciona (Técnico)¶
Coverlet - ExcludeByFile¶
O parâmetro ExcludeByFile do Coverlet:
- Analisa todos os arquivos durante a execução dos testes
- Filtra arquivos que correspondem aos padrões:
**/*OpenApi*.generated.cs→ OpenApi source generators**/System.Runtime.CompilerServices*.cs→ Compiler services**/*RegexGenerator.g.cs→ Regex source generators- Não coleta coverage desses arquivos
- Gera coverage.cobertura.xml já SEM código gerado
- ReportGenerator recebe dados limpos e mostra percentuais reais
Fluxo de Execução¶
┌─────────────────────────────────────────────────────────────┐
│ 1. dotnet test (com ExcludeByFile) │
│ ↓ │
│ Executa testes + Coverlet instrumenta código │
│ ↓ │
│ Coverlet IGNORA arquivos *.generated.cs │
│ ↓ │
│ Gera coverage.cobertura.xml (SEM código gerado) │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 2. ReportGenerator │
│ ↓ │
│ Lê coverage.cobertura.xml (dados JÁ limpos) │
│ ↓ │
│ Calcula percentuais com dados REAIS │
│ ↓ │
│ Gera index.html com coverage VERDADEIRO │
└─────────────────────────────────────────────────────────────┘
Por Que Funciona Agora?¶
Tentativa Anterior (FALHOU):
❌ Problema: XML já tinha dados misturados, não dá para recalcularSolução Atual (FUNCIONA):
✅ Sucesso: XML já vem limpo desde a origem🚀 Como Testar Localmente¶
Opção 1: Comando dotnet test (Recomendado)¶
# Roda testes + gera relatório limpo (~25 minutos)
dotnet test --collect:"XPlat Code Coverage" --settings config/coverage.runsettings
Resultado:
- coverage/report/index.html - Relatório com números REAIS
- Coverage esperado: ~45-55% (vs 27.9% anterior)
Opção 2: Manual (Passo a Passo)¶
# 1. Limpar coverage anterior
Remove-Item coverage -Recurse -Force
# 2. Rodar testes com exclusões
dotnet test `
--collect:"XPlat Code Coverage" `
-- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.ExcludeByFile="**/*OpenApi*.generated.cs,**/System.Runtime.CompilerServices*.cs,**/*RegexGenerator.g.cs"
# 3. Gerar relatório
reportgenerator `
-reports:"coverage/**/coverage.cobertura.xml" `
-targetdir:"coverage/report" `
-reporttypes:"Html;TextSummary"
# 4. Ver resultado
Get-Content coverage/report/Summary.txt | Select-Object -First 20
📋 Validação - Como Confirmar Que Funcionou?¶
1. Verificar Documents.API¶
ANTES (com generated):
DEPOIS (sem generated):
2. Verificar Namespaces Excluídos¶
No relatório HTML, você NÃO verá mais:
- ❌ Microsoft.AspNetCore.OpenApi.Generated
- ❌ System.Runtime.CompilerServices
- ❌ System.Text.RegularExpressions.Generated (exceto se houver código manual)
3. Verificar Coverage Global¶
⚙️ Pipeline CI/CD - Vai Funcionar Automaticamente?¶
✅ SIM - Já Configurado!¶
Arquivo: .github/workflows/ci-cd.yml
Mudanças Aplicadas:
- ✅ Todos os dotnet test têm ExcludeByFile
- ✅ ReportGenerator removeu filtros redundantes
- ✅ Nota explicativa adicionada
Próximo Push/PR: 1. Pipeline roda com nova configuração 2. Coverage é coletado SEM código gerado 3. Artefatos mostram percentuais REAIS 4. Badge de coverage atualiza automaticamente
Como Verificar na Pipeline¶
- Fazer commit e push desta branch
- Ver Actions no GitHub
- Baixar artifact "code-coverage"
- Abrir index.html e verificar Documents.API ≈ 82%
📊 Comparação Lado a Lado¶
Documents.API (Exemplo Real)¶
| Componente | Linhas | Coverable | Covered | Coverage |
|---|---|---|---|---|
| Endpoints manuais | 361 | 154 | 127 | 82.5% ✅ |
| OpenApi.Generated | 1,507 | 1,286 | 0 | 0.0% ❌ |
| TOTAL (misturado) | 1,868 | 1,440 | 127 | 8.8% ⚠️ |
Após Exclusão¶
| Componente | Linhas | Coverable | Covered | Coverage |
|---|---|---|---|---|
| Endpoints manuais | 361 | 154 | 127 | 82.5% ✅ |
Resultado: 82.5% é o número REAL que reflete o código escrito manualmente!
🎓 Lições Aprendidas¶
1. Filtrar na ORIGEM, não no DESTINO¶
- ✅ Coverlet ExcludeByFile (coleta)
- ❌ ReportGenerator classfilters (visualização)
2. Código Gerado Distorce Coverage¶
- OpenApi.Generated: 1,286 linhas com 0% coverage
- Impacto: 82.5% → 8.8% (9.4× menor!)
3. Validar com Cálculos Manuais¶
- Usuário calculou 84.1% manualmente
- Real é 82.5% (diferença de apenas 1.6%)
- Conclusão: Sempre questione números estranhos!
📁 Arquivos Modificados¶
- ✅
.github/workflows/ci-cd.yml- Pipeline atualizada - ✅
dotnet test --collect:"XPlat Code Coverage"- Comando local - ✅
docs/testing/coverage-report-explained.md- Documentação completa - ✅
docs/testing/coverage-analysis-dec-2025.md- Análise detalhada
🚦 Próximos Passos¶
Imediato (Hoje)¶
- ✅ Configuração aplicada
- ⏳ Rodar localmente (opcional - 25 min)
- ⏳ Commit + Push para testar pipeline
Próxima Sprint¶
- Monitorar coverage real na pipeline
- Ajustar targets de coverage (45%+ atual, meta 60%+)
- Criar dashboards com métricas limpas
❓ FAQ¶
P: "Preciso rodar novamente localmente?"¶
R: Opcional. A pipeline já está configurada. Se quiser ver os números agora: dotnet test --collect:"XPlat Code Coverage" --settings config/coverage.runsettings
P: "E se eu quiser incluir código gerado?"¶
R: Remova o parâmetro ExcludeByFile dos comandos dotnet test. Mas não recomendado - distorce métricas.
P: "Vai funcionar no SonarQube/Codecov?"¶
R: SIM! Eles leem coverage.cobertura.xml que já virá limpo.
P: "E os targets de coverage (80%)?"¶
R: Ajuste para valores realistas baseados no novo baseline:
Targets Progressivos (alinhados com padrões da indústria):
- Mínimo (CI warning): 70% line, 60% branch, 70% method
- Recomendado: 85% line, 75% branch, 85% method
- Excelente: 90%+ line, 80%+ branch, 90%+ method
Nota: Os números iniciais (~45-55%) são intermediários. O projeto deve evoluir para o mínimo de 70% em código crítico.
Nota: Formato threshold: "line,branch,method" (percentuais mínimos)
Conclusão: ✅ Tudo configurado! Pipeline e script local vão gerar coverage REAL excluindo código gerado. Próximo push já mostrará ~45-55% em vez de 27.9%.
Análise de Gaps de Cobertura - Caminho para 90%¶
Data: 9 de dezembro de 2025
Cobertura Atual: 89.1%
Meta: 90%
Gap: +0.9%
Linhas Necessárias: ~66 linhas adicionais (de 794 não cobertas)
📊 Sumário Executivo¶
Para aumentar a cobertura de 89.1% para 90%, precisamos cobrir aproximadamente 66 linhas adicionais. A estratégia recomendada é focar nas áreas de maior impacto que estão mais próximas de 90% ou têm muitas linhas não cobertas.
Prioridades (Maior ROI):¶
- ApiService (85.1%) - 794 linhas não cobertas
- Documents.Infrastructure (84.1%) - Serviços Azure com baixa cobertura
- Shared (78.4%) - Componentes de infraestrutura
- Users.API (79%) - Extensions e Authorization
🎯 Áreas Críticas para Foco¶
1. ApiService (85.1% → 90%+) - PRIORIDADE MÁXIMA¶
Program.cs (28.1%) 🔴¶
Impacto: ALTO - Arquivo de entrada principal
Linhas Não Cobertas:
- Linhas 100-139: Configuração de middleware (try/catch, logging final)
- Método ConfigureMiddlewareAsync (linhas 100+)
- Método LogStartupComplete (não visualizado)
- Método HandleStartupException (não visualizado)
- Método CloseLogging (não visualizado)
Solução: - Criar testes de integração para startup/shutdown - Testar cenários de erro no startup - Testes para ambiente Testing vs Production
Estimativa: +40 linhas cobertas
RateLimitingMiddleware.cs (42.2%) 🔴¶
Impacto: ALTO - Segurança e performance
Linhas Não Cobertas (estimadas):
- Método GetEffectiveLimit (linha 103+): Lógica de limites por endpoint
- Limites customizados por usuário autenticado
- Whitelist de IPs
- Cenários de rate limit excedido
- Warning threshold (80% do limite)
Solução:
// Testes necessários:
// 1. Rate limit excedido para IP não autenticado
// 2. Rate limit excedido para usuário autenticado
// 3. IP whitelisted - bypass rate limit
// 4. Endpoint-specific limits
// 5. Approaching limit warning (80%)
// 6. Window expiration e reset
Estimativa: +60 linhas cobertas
ExampleSchemaFilter.cs ✅ REMOVIDO (13 Dez 2025)¶
Razão: Código problemático removido permanentemente do projeto
Solução: - Opção 1: Implementar migração para Swashbuckle 10.x e testar - Opção 2: Excluir do coverage (código temporariamente desabilitado) - Recomendação: Excluir do coverage por enquanto
Estimativa: N/A (código desabilitado)
2. Documents.Infrastructure (84.1% → 95%+)¶
AzureDocumentIntelligenceService.cs (33.3%) 🔴¶
Impacto: ALTO - Funcionalidade crítica de OCR
Linhas Não Cobertas (estimadas): - Cenários de erro na análise de documentos - Timeout handling - Retry logic - Parsing de resultados de OCR - Validação de campos extraídos
Solução:
// Testes com Mock do Azure Document Intelligence:
// 1. AnalyzeDocumentAsync - sucesso
// 2. AnalyzeDocumentAsync - timeout
// 3. AnalyzeDocumentAsync - erro de autenticação
// 4. Parsing de campos extraídos (CPF, RG, CNH)
// 5. Documento inválido/ilegível
Estimativa: +50 linhas cobertas
DocumentsDbContextFactory.cs (0%) 🔴¶
Impacto: BAIXO - Usado apenas em design-time
Solução: - Opção 1: Criar teste de factory para migrations - Opção 2: Excluir do coverage (código de design-time) - Recomendação: Excluir do coverage
Estimativa: N/A (design-time code)
Documents.API.Extensions (37%) 🟡¶
Impacto: MÉDIO
Linhas Não Cobertas: - Registro de serviços não testado - Configuração de DI container
Solução:
// Teste de integração:
// 1. Verificar se todos os serviços estão registrados
// 2. Verificar se endpoints estão mapeados
// 3. Health checks configurados
Estimativa: +15 linhas cobertas
3. Shared (78.4% → 85%+)¶
PostgreSqlExceptionProcessor.cs (18.1%) 🔴¶
Impacto: ALTO - Tratamento de erros de banco
Linhas Não Cobertas: - Processamento de diferentes códigos de erro PostgreSQL - Foreign key violations - Unique constraint violations - Not null violations - Outros erros específicos do PostgreSQL
Solução:
// Testes unitários:
// 1. ProcessException - ForeignKeyViolation (23503)
// 2. ProcessException - UniqueViolation (23505)
// 3. ProcessException - NotNullViolation (23502)
// 4. ProcessException - CheckViolation (23514)
// 5. ProcessException - UnknownError
Estimativa: +40 linhas cobertas
GlobalExceptionHandler.cs (43.3%) 🟡¶
Impacto: ALTO - Tratamento global de erros
Linhas Não Cobertas: - Diferentes tipos de exceções - Formatação de respostas de erro - Logging de exceções
Solução:
// Testes:
// 1. Handle ValidationException
// 2. Handle NotFoundException
// 3. Handle ForbiddenAccessException
// 4. Handle BusinessRuleException
// 5. Handle Exception genérica
// 6. Verificar logs e status codes
Estimativa: +35 linhas cobertas
Extensions e Registration (20-50%)¶
Impacto: MÉDIO
Classes:
- ModuleServiceRegistrationExtensions (20%)
- ServiceCollectionExtensions (78.5%)
- Database.Extensions (52.8%)
- Logging.LoggingConfigurationExtensions (56.9%)
Solução: - Testes de integração para verificar registro de serviços - Mock de IServiceCollection para validar chamadas
Estimativa: +30 linhas cobertas
4. DbContextFactory Classes (0%) - BAIXA PRIORIDADE¶
Classes com 0% Coverage:
- DocumentsDbContextFactory
- ProvidersDbContextFactory
- SearchProvidersDbContextFactory
- ServiceCatalogsDbContextFactory
- UsersDbContextFactory
Análise: Todas são classes de design-time usadas para migrations do EF Core.
Recomendação: Excluir do coverage adicionando ao .runsettings:
Impacto: Isso aumentaria a cobertura em ~0.3-0.5% instantaneamente sem criar testes.
5. Outras Áreas de Baixa Cobertura¶
SearchProvidersDbContext (43.4%) 🟡¶
Solução: Testes de queries e configurações
Providers.Infrastructure.ProviderRepository (87.5%) 🟢¶
Solução: Testar métodos específicos não cobertos
SearchProviders.Application.ModuleApi (73.9%) 🟡¶
Solução: Testar cenários de erro na API
📋 Plano de Ação Recomendado¶
Fase 1: Quick Wins (Alcançar 90%) - 1-2 dias¶
-
Excluir DbContextFactory do coverage (+0.5%)
-
Testar RateLimitingMiddleware (+0.3%)
- Criar
RateLimitingMiddlewareTests.cs -
10-15 testes cobrindo principais cenários
-
Testar AzureDocumentIntelligenceService (+0.2%)
- Criar
AzureDocumentIntelligenceServiceTests.cs - Mock do Azure SDK
- Testar cenários de sucesso e erro
Total Fase 1: ~1.0% (89.1% → 90.1%) ✅
Fase 2: Consolidação (Alcançar 92%) - 2-3 dias¶
- Testar Program.cs startup (+0.2%)
- Integration tests para startup/shutdown
-
Testar diferentes ambientes
-
Testar PostgreSqlExceptionProcessor (+0.2%)
- Todos os códigos de erro PostgreSQL
-
Cenários de fallback
-
Testar GlobalExceptionHandler (+0.2%)
- Diferentes tipos de exceções
-
Validar respostas HTTP
-
Testar Extensions de registro (+0.2%)
- ServiceCollectionExtensions
- ModuleServiceRegistrationExtensions
Total Fase 2: ~0.8% (90.1% → 90.9%)
Fase 3: Otimização (Alcançar 93%+) - 3-5 dias¶
- Cobertura de Shared.Messaging (+0.3%)
- Cobertura de Shared.Database (+0.2%)
- Módulos API Extensions (+0.2%)
Total Fase 3: ~0.7% (90.9% → 91.6%)
🎯 Resumo: Como Alcançar 90%¶
Estratégia de Menor Esforço (Recomendada):¶
- Excluir DbContextFactory (5 min)
-
Coverage: 89.1% → 89.6%
-
Testar RateLimitingMiddleware (4-6 horas)
-
Coverage: 89.6% → 89.9%
-
Testar AzureDocumentIntelligenceService (3-4 horas)
- Coverage: 89.9% → 90.1%
Total: ~1 dia de trabalho para alcançar 90%+ ✅
📝 Notas Importantes¶
Por que seus 27 testes não aumentaram coverage?¶
DocumentsModuleApi já estava em 100% devido a: - Testes de integração E2E - Testes de API endpoints - Testes de handlers
Seus testes unitários cobriram os mesmos code paths já cobertos por testes de nível superior.
Dica para Maximizar Coverage:¶
- Olhe o relatório HTML (
coverage-github/report/index.html) - Identifique linhas vermelhas (não cobertas)
- Foque em código de produção (não DbContextFactory, Program.cs opcional)
- Teste cenários de erro (onde está 70% do gap)
🔧 Ferramentas de Apoio¶
Ver linhas não cobertas:¶
# Abrir relatório HTML
start coverage-github/report/index.html
# Ver resumo text
cat coverage-github/report/Summary.txt | Select-Object -First 100
Gerar coverage local:¶
# Rodar pipeline localmente
dotnet test --collect:"XPlat Code Coverage" --results-directory ./coverage
# Gerar relatório HTML
reportgenerator `
-reports:"coverage/aggregate/Cobertura.xml" `
-targetdir:"coverage/report" `
-reporttypes:"Html;TextSummary"
📚 Referências¶
- Relatório de Coverage Atual:
coverage-github/report/index.html(gerado via CI/CD) - Pipeline CI/CD:
.github/workflows/ci-cd.yml - Configuração Coverlet:
config/coverlet.json - Coverage local:
dotnet test --collect:"XPlat Code Coverage"