crap-analysis
コードの変更リスクと複雑さを分析し、テストされていない箇所を特定することで、品質改善が必要なリスクの高いコード領域を効率的に見つけ出すSkill。
📜 元の英語説明(参考)
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.
🇯🇵 日本人クリエイター向け解説
コードの変更リスクと複雑さを分析し、テストされていない箇所を特定することで、品質改善が必要なリスクの高いコード領域を効率的に見つけ出すSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o crap-analysis.zip https://jpskill.com/download/8703.zip && unzip -o crap-analysis.zip && rm crap-analysis.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/8703.zip -OutFile "$d\crap-analysis.zip"; Expand-Archive "$d\crap-analysis.zip" -DestinationPath $d -Force; ri "$d\crap-analysis.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
crap-analysis.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
crap-analysisフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
CRAPスコア分析
このSkillを使用するタイミング
このSkillは、以下の場合に使用します。
- 変更前にコード品質とテストカバレッジを評価する
- リファクタリングまたはテストが必要な高リスクのコードを特定する
- .NETプロジェクトのカバレッジ収集を設定する
- リスクに基づいてテストするコードの優先順位付けを行う
- CI/CDパイプラインのカバレッジ閾値を設定する
CRAPとは?
CRAPスコア = 複雑度 x (1 - カバレッジ)^2
CRAP(Change Risk Anti-Patterns)スコアは、循環的複雑度とテストカバレッジを組み合わせて、リスクの高いコードを特定します。
| CRAPスコア | リスクレベル | 必要なアクション |
|---|---|---|
| < 5 | 低 | 十分にテストされ、保守可能なコード |
| 5-30 | 中 | 許容範囲だが、複雑さに注意 |
| > 30 | 高 | テストまたはリファクタリングが必要 |
CRAPが重要な理由
- 高い複雑度 + 低いカバレッジ = 危険: 理解が難しく、テストされていないコードは変更するリスクが高い
- 複雑さだけでは不十分: 100%のカバレッジを持つ複雑なメソッドは、0%のカバレッジを持つ単純なメソッドよりも安全
- 労力の集中: 単純なgetter/setterではなく、複雑なコードのテストを優先する
CRAPスコアの例
| メソッド | 複雑度 | カバレッジ | 計算 | 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.runsettings
リポジトリのルートに coverage.runsettings ファイルを作成します。CRAPスコアの計算には、OpenCover形式が必要です。これは、循環的複雑度のメトリクスが含まれているためです。
<?xml version="1.0" encoding="utf-8" ?>
<RunSettings>
<DataCollectionRunSettings>
<DataCollectors>
<DataCollector friendlyName="XPlat code coverage">
<Configuration>
<!-- OpenCover format includes cyclomatic complexity for CRAP scores -->
<Format>cobertura,opencover</Format>
<!-- Exclude test and benchmark assemblies -->
<Exclude>[*.Tests]*,[*.Benchmark]*,[*.Migrations]*</Exclude>
<!-- Exclude generated code, obsolete members, and explicit exclusions -->
<ExcludeByAttribute>Obsolete,GeneratedCodeAttribute,CompilerGeneratedAttribute,ExcludeFromCodeCoverageAttribute</ExcludeByAttribute>
<!-- Exclude source-generated files, Blazor generated code, and migrations -->
<ExcludeByFile>**/obj/**/*,**/*.g.cs,**/*.designer.cs,**/*.razor.g.cs,**/*.razor.css.g.cs,**/Migrations/**/*</ExcludeByFile>
<!-- Exclude test projects -->
<IncludeTestAssembly>false</IncludeTestAssembly>
<!-- Optimization flags -->
<SingleHit>false</SingleHit>
<UseSourceLink>true</UseSourceLink>
<SkipAutoProps>true</SkipAutoProps>
</Configuration>
</DataCollector>
</DataCollectors>
</DataCollectionRunSettings>
</RunSettings>
主要な構成オプション
| オプション | 目的 |
|---|---|
Format |
複雑度メトリクスには opencover を含める必要があります |
Exclude |
パターンでテスト/ベンチマークアセンブリを除外します |
ExcludeByAttribute |
生成されたコード、廃止されたコード、および明示的に除外されたコードをスキップします(ExcludeFromCodeCoverageAttribute を含む) |
ExcludeByFile |
ソース生成されたファイル、Blazorコンポーネント、および移行をスキップします |
SkipAutoProps |
自動プロパティを分岐としてカウントしません |
ReportGeneratorのインストール
リスクホットスポットを含むHTMLレポートを生成するために、ReportGeneratorをローカルツールとしてインストールします。
.config/dotnet-tools.jsonに追加
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-reportgenerator-globaltool": {
"version": "5.4.5",
"commands": ["reportgenerator"],
"rollForward": false
}
}
}
次に、復元します。
dotnet tool restore
またはグローバルにインストール
dotnet tool install --global dotnet-reportgenerator-globaltool
カバレッジの収集
カバレッジ収集でテストを実行
# Clean previous results
rm -rf coverage/ TestResults/
# Run unit tests with coverage
dotnet test tests/MyApp.Tests.Unit \
--settings coverage.runsettings \
--collect:"XPlat Code Coverage" \
--results-directory ./TestResults
# Run integration tests (optional, adds to coverage)
dotnet test tests/MyApp.Tests.Integration \
--settings coverage.runsettings \
--collect:"XPlat Code Coverage" \
--results-directory ./TestResults
HTMLレポートの生成
dotnet reportgenerator \
-reports:"TestResults/**/coverage.opencover.xml" \
-targetdir:"coverage" \
-reporttypes:"Html;TextSummary;MarkdownSummaryGithub"
レポートの種類
| タイプ | 説明 | 出力 |
|---|---|---|
Html |
完全なインタラクティブレポート | coverage/index.html |
TextSummary |
プレーンテキストの概要 | coverage/Summary.txt |
MarkdownSummaryGithub |
GitHub互換のMarkdown | coverage/SummaryGithub.md |
Badges |
README用のSVGバッジ | coverage/badge_*.svg |
Cobertura |
マージされたCobertura XML | coverage/Cobertura.xml |
レポートの読み方
リスクホットスポットセクション
HTMLレポートには、複雑さでソートされたメソッドを示すリスクホットスポットセクションが含まれています。
- 循環的複雑度: コードを通る独立したパスの数(if/else、switch case、ループ)
- NPath複雑度: 非循環的な実行パスの数(ネストによる指数関数的な増加)
- Crap Score: 複雑さとカバレッジから計算
結果の解釈
Risk Hotspots
─────────────
Method Complexity Coverage Crap Score
──────────────────────────────────────────────────────────────────
DataImporter.ParseRecord() 54 52% 12.4
AuthService.ValidateToken() 32 0% 32.0 ← HIGH RISK
OrderProcessor.Calculate() 28 85% 1.3
(原文がここで切り詰められています) 📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
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.
<?xml version="1.0" encoding="utf-8" ?>
<RunSettings>
<DataCollectionRunSettings>
<DataCollectors>
<DataCollector friendlyName="XPlat code coverage">
<Configuration>
<!-- OpenCover format includes cyclomatic complexity for CRAP scores -->
<Format>cobertura,opencover</Format>
<!-- Exclude test and benchmark assemblies -->
<Exclude>[*.Tests]*,[*.Benchmark]*,[*.Migrations]*</Exclude>
<!-- Exclude generated code, obsolete members, and explicit exclusions -->
<ExcludeByAttribute>Obsolete,GeneratedCodeAttribute,CompilerGeneratedAttribute,ExcludeFromCodeCoverageAttribute</ExcludeByAttribute>
<!-- Exclude source-generated files, Blazor generated code, and migrations -->
<ExcludeByFile>**/obj/**/*,**/*.g.cs,**/*.designer.cs,**/*.razor.g.cs,**/*.razor.css.g.cs,**/Migrations/**/*</ExcludeByFile>
<!-- Exclude test projects -->
<IncludeTestAssembly>false</IncludeTestAssembly>
<!-- Optimization flags -->
<SingleHit>false</SingleHit>
<UseSourceLink>true</UseSourceLink>
<SkipAutoProps>true</SkipAutoProps>
</Configuration>
</DataCollector>
</DataCollectors>
</DataCollectionRunSettings>
</RunSettings>
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
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-reportgenerator-globaltool": {
"version": "5.4.5",
"commands": ["reportgenerator"],
"rollForward": false
}
}
}
Then restore:
dotnet tool restore
Or Install Globally
dotnet tool install --global dotnet-reportgenerator-globaltool
Collecting Coverage
Run Tests with Coverage Collection
# Clean previous results
rm -rf coverage/ TestResults/
# Run unit tests with coverage
dotnet test tests/MyApp.Tests.Unit \
--settings coverage.runsettings \
--collect:"XPlat Code Coverage" \
--results-directory ./TestResults
# Run integration tests (optional, adds to coverage)
dotnet test tests/MyApp.Tests.Integration \
--settings coverage.runsettings \
--collect:"XPlat Code Coverage" \
--results-directory ./TestResults
Generate HTML Report
dotnet reportgenerator \
-reports:"TestResults/**/coverage.opencover.xml" \
-targetdir:"coverage" \
-reporttypes:"Html;TextSummary;MarkdownSummaryGithub"
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
Risk Hotspots
─────────────
Method Complexity Coverage Crap Score
──────────────────────────────────────────────────────────────────
DataImporter.ParseRecord() 54 52% 12.4
AuthService.ValidateToken() 32 0% 32.0 ← HIGH RISK
OrderProcessor.Calculate() 28 85% 1.3
UserService.CreateUser() 15 100% 0.0
Action items:
ValidateToken()has CRAP > 30 with 0% coverage - test immediately or refactorParseRecord()is complex but has decent coverage - acceptableCreateUser()andCalculate()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:
<Project>
<PropertyGroup>
<!-- Coverage thresholds for CI enforcement -->
<CoverageThresholdLine>80</CoverageThresholdLine>
<CoverageThresholdBranch>60</CoverageThresholdBranch>
</PropertyGroup>
</Project>
CI/CD Integration
GitHub Actions
name: Coverage
on:
pull_request:
branches: [main, dev]
jobs:
coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
- name: Restore tools
run: dotnet tool restore
- name: Run tests with coverage
run: |
dotnet test \
--settings coverage.runsettings \
--collect:"XPlat Code Coverage" \
--results-directory ./TestResults
- name: Generate report
run: |
dotnet reportgenerator \
-reports:"TestResults/**/coverage.opencover.xml" \
-targetdir:"coverage" \
-reporttypes:"Html;MarkdownSummaryGithub;Cobertura"
- name: Upload coverage report
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage/
- name: Add coverage to PR
uses: marocchino/sticky-pull-request-comment@v2
with:
path: coverage/SummaryGithub.md
Azure Pipelines
- task: DotNetCoreCLI@2
displayName: 'Run tests with coverage'
inputs:
command: 'test'
arguments: '--settings coverage.runsettings --collect:"XPlat Code Coverage" --results-directory $(Build.SourcesDirectory)/TestResults'
- task: DotNetCoreCLI@2
displayName: 'Generate coverage report'
inputs:
command: 'custom'
custom: 'reportgenerator'
arguments: '-reports:"$(Build.SourcesDirectory)/TestResults/**/coverage.opencover.xml" -targetdir:"$(Build.SourcesDirectory)/coverage" -reporttypes:"HtmlInline_AzurePipelines;Cobertura"'
- task: PublishCodeCoverageResults@2
displayName: 'Publish coverage'
inputs:
codeCoverageTool: 'Cobertura'
summaryFileLocation: '$(Build.SourcesDirectory)/coverage/Cobertura.xml'
Quick Reference
One-Liner Commands
# Full analysis workflow
rm -rf coverage/ TestResults/ && \
dotnet test --settings coverage.runsettings \
--collect:"XPlat Code Coverage" \
--results-directory ./TestResults && \
dotnet reportgenerator \
-reports:"TestResults/**/coverage.opencover.xml" \
-targetdir:"coverage" \
-reporttypes:"Html;TextSummary"
# View summary
cat coverage/Summary.txt
# Open HTML report (Linux)
xdg-open coverage/index.html
# Open HTML report (macOS)
open coverage/index.html
# Open HTML report (Windows)
start coverage/index.html
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