crap-analysis
Analyze code coverage and CRAP (Change Risk Anti-Patterns) scores to identify high-risk code. Use OpenCover format with ReportGenerator for Risk Hotspots showing cyclomatic complexity and untested code paths.
By aaronontheweb · 501 installs
npx skills add aaronontheweb/dotnet-skills --skill crap-analysis
Source repository · Upstream listing
CRAP Score Analysis
When to Use This Skill
Use this skill when:
Evaluating code quality and test coverage before changes
Identifying high risk code that needs refactoring or testing
Setting up coverage collection for a .NET project
Prioritizing which code to test based on risk
Establishing coverage thresholds for CI/CD pipelines
What is CRAP?
CRAP Score = Complexity x (1 Coverage)^2
The CRAP (Change Risk Anti Patterns) score combines cyclomatic complexity with test coverage to identify risky code.
CRAP Score Risk Level Action Required
< 5 Low Well tested, maintainable code
5 30 Medium Acceptable but watch complexity
30 High Needs tests or refactoring
Why CRAP Matters
High complexity + low coverage = danger : Code that's hard to understand AND untested is risky to modify
Complexity alone isn't enough : A complex method with 100% coverage is safer than a simple method with 0%
Focuses effort : Prioritize testing on complex code, not simple getters/setters
CRAP Score Examples
Method Complexity Coverage Calculation CRAP
GetUserId() 1 0% 1 x (1 0)^2 1
ParseToken() 54 52% 54 x (1 0.52)^2 12.4
ValidateForm() 20 0% 20 x (1 0)^2 20
ProcessOrder() 45 20% 45 x (1 0.20)^2 28.8
ImportData() 80 10% 80 x (1 0.10)^2 64.8
Coverage Collection Setup
coverage.runsettings
Create a coverage.runsettings file in your repository root. The OpenCover format is required for CRAP score calculation because it includes cyclomatic complexity metrics.
Key Configuration Options
Option Purpose
Format Must include opencover for complexity metrics
Exclude Exclude test/benchmark assemblies by pattern
ExcludeByAttribute Skip generated, obsolete, and explicitly excluded code (includes ExcludeFromCodeCoverageAttribute )
ExcludeByFile Skip source generated files, Blazor components, and migrations
SkipAutoProps Don't count auto properties as branches
ReportGenerator Installation
Install ReportGenerator as a local tool for generating HTML reports with Risk Hotspots.
Add to .config/dotnet tools.json
Then restore:
Or Install Globally
Collecting Coverage
Run Tests with Coverage Collection
Generate HTML Report
Report Types
Type Description Output
Html Full interactive report coverage/index.html
TextSummary Plain text summary coverage/Summary.txt
MarkdownSummaryGithub GitHub compatible markdown coverage/SummaryGithub.md
Badges SVG badges for README coverage/badge .svg
Cobertura Merged Cobertura XML coverage/Cobertura.xml
Reading the Report
Risk Hotspots Section
The HTML report includes a Risk Hotspots section showing methods sorted by complexity:
Cyclomatic Complexity : Number of independent paths through code (if/else, switch cases, loops)
NPath Complexity : Number of acyclic execution paths (exponential growth with nesting)
Crap Score : Calculated from complexity and coverage
Interpreting Results
Action items:
ValidateToken() has CRAP 30 with 0% coverage test immediately or refactor
ParseRecord() is complex but has decent coverage acceptable
CreateUser() and Calculate() are well tested safe to modify
Coverage Thresholds
Recommended Standards
Coverage Type Target Action
Line Coverage 80% Good for most projects
Branch Coverage 60% Catches conditional logic
CRAP Score < 30 Maximum for new code
Configuring Thresholds
Create coverage.props in your repository:
CI/CD Integration
GitHub Actions
Azure Pipelines
Quick Reference
One Liner Commands
Project Standards
Metric New Code Legacy Code
Line Coverage 80%+ 60%+ (improve gradually)
Branch Coverage 60%+ 40%+ (improve gradually)
Maximum CRAP 30 Document exceptions
High risk methods Must have tests Add tests before modifying
What Gets Excluded
The recommended coverage.runsettings excludes:
Pattern Reason
[ .Tests] Test assemblies aren't production code
[ .Benchmark] Benchmark projects
[ .Migrations] Database migrations (generated)
GeneratedCodeAttribute Source generators
CompilerGeneratedAttribute Compiler generated code
ExcludeFromCodeCoverageAttribute Explicit developer opt out
.g.cs , .designer.cs Generated files
.razor.g.cs Blazor component generated code
.razor.css.g.cs Blazor CSS isolation generated code
/Migrations/ / EF Core migrations (auto generated)
SkipAutoProps Auto properties (trivial branches)
When to Update Thresholds
Lower thresholds temporarily for:
Legacy codebases being modernized (document in README)
Generated code that can't be modified
Third party wrapper code
Never lower thresholds for:
"It's too hard to test" refactor instead
"We'll add tests later" add them now
New features should meet standards from the start
Additional Resources
Coverlet Documentation : https://github.com/coverlet coverage/coverlet
ReportGenerator : https://github.com/danielpalme/ReportGenerator
CRAP Score Original Paper : http://www.artima.com/weblogs/viewpost.jsp?thread=215899