crap-score
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCRAP Score Analysis
CRAP得分分析
Calculate CRAP (Change Risk Anti-Patterns) scores for .NET methods to identify code that is both complex and undertested.
为.NET方法计算CRAP(变更风险反模式)得分,识别既复杂又缺乏测试的代码。
Background
背景
The CRAP score combines cyclomatic complexity and code coverage into a single metric:
$$\text{CRAP}(m) = \text{comp}(m)^2 \times (1 - \text{cov}(m))^3 + \text{comp}(m)$$
Where:
- $\text{comp}(m)$ = cyclomatic complexity of method $m$
- $\text{cov}(m)$ = code coverage ratio (0.0 to 1.0) of method $m$
| CRAP Score | Risk Level | Interpretation |
|---|---|---|
| < 5 | Low | Simple and well-tested |
| 5-15 | Moderate | Acceptable for most code |
| 15-30 | High | Needs more tests or simplification |
| > 30 | Critical | Refactor and add coverage urgently |
A method with 100% coverage has CRAP = complexity (the minimum). A method with 0% coverage has CRAP = complexity^2 + complexity.
CRAP得分将圈复杂度和代码覆盖率结合为单一指标:
$$\text{CRAP}(m) = \text{comp}(m)^2 \times (1 - \text{cov}(m))^3 + \text{comp}(m)$$
其中:
- $\text{comp}(m)$ = 方法$m$的圈复杂度
- $\text{cov}(m)$ = 方法$m$的代码覆盖率(取值范围0.0到1.0)
| CRAP得分 | 风险等级 | 释义 |
|---|---|---|
| < 5 | 低 | 代码简单且测试覆盖完善 |
| 5-15 | 中等 | 对大部分代码来说可接受 |
| 15-30 | 高 | 需要补充测试或简化代码 |
| > 30 | 严重 | 急需重构并补充测试覆盖率 |
覆盖率100%的方法CRAP得分等于其复杂度(最低值)。覆盖率为0%的方法CRAP得分等于复杂度的平方加复杂度。
When to Use
适用场景
- User wants to assess which methods are risky due to low coverage and high complexity
- User asks for CRAP score of specific methods, classes, or files
- User wants to prioritize which code to test next
- User wants to evaluate test quality beyond simple coverage percentages
- 用户需要评估哪些方法因覆盖率低、复杂度高存在风险
- 用户要求获取指定方法、类或文件的CRAP得分
- 用户需要确定后续测试的优先级
- 用户需要在简单覆盖率百分比之外评估测试质量
When Not to Use
不适用场景
- User just wants to run tests (use skill)
run-tests - User wants to write new tests (use skill or general coding assistance)
writing-mstest-tests - User only wants a coverage percentage without complexity analysis
- 用户仅需要运行测试(使用skill)
run-tests - 用户需要编写新测试(使用skill或通用代码协助能力)
writing-mstest-tests - 用户仅需要覆盖率百分比,不需要复杂度分析
Inputs
输入参数
| Input | Required | Description |
|---|---|---|
| Target scope | Yes | Method name, class name, or file path to analyze |
| Test project path | No | Path to the test project. Defaults to discovering test projects in the solution. |
| Source project path | No | Path to the source project under analysis |
| 输入项 | 是否必填 | 描述 |
|---|---|---|
| 目标范围 | 是 | 要分析的方法名、类名或文件路径 |
| 测试项目路径 | 否 | 测试项目的路径。默认会自动发现解决方案中的测试项目。 |
| 源项目路径 | 否 | 待分析的源项目路径 |
Workflow
工作流程
Step 1: Collect code coverage data
步骤1:收集代码覆盖率数据
If no coverage data exists yet (no Cobertura XML available), always run with coverage collection first and mention the exact command in your response. Do not skip this step -- CRAP scores require coverage data.
dotnet testCheck the test project's for the coverage package, then run the appropriate command:
.csproj| Coverage Package | Command | Output Location |
|---|---|---|
| | Typically under |
| | |
| | |
如果尚无覆盖率数据(无可用的Cobertura XML),必须先运行带覆盖率收集功能的命令,并在响应中说明具体命令。不得跳过此步骤——CRAP得分必须基于覆盖率数据计算。
dotnet test检查测试项目的文件确认使用的覆盖率包,然后运行对应命令:
.csproj| 覆盖率包 | 命令 | 输出位置 |
|---|---|---|
| | 通常位于 |
| | |
| | |
Step 2: Compute cyclomatic complexity
步骤2:计算圈复杂度
Analyze the target source files to determine cyclomatic complexity per method. Count the following decision points (each adds 1 to the base complexity of 1):
| Construct | Example |
|---|---|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| Pattern match arm | |
Base complexity is 1 for every method. Each decision point adds 1.
When analyzing, read the source file and count these constructs per method. Report the breakdown.
分析目标源文件,确定每个方法的圈复杂度。统计以下决策点(每出现一个,就在基础复杂度1的基础上加1):
| 语法结构 | 示例 |
|---|---|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| 模式匹配分支 | |
每个方法的基础复杂度为1,每出现一个上述决策点加1。
分析时读取源文件,按方法统计上述结构的数量,并给出统计明细。
Step 3: Extract per-method coverage from Cobertura XML
步骤3:从Cobertura XML中提取每个方法的覆盖率
Parse the Cobertura XML to find each method's attribute under the target element. If is not available at method level, compute it from the elements:
line-rate<class>line-rate<lines>$$\text{cov}(m) = \frac{\text{lines with hits} > 0}{\text{total lines}}$$
Method names in Cobertura may differ from source (async methods, lambdas). Match by line ranges when names don't align.
解析Cobertura XML,找到目标元素下每个方法的属性。如果方法层级没有属性,可通过元素计算:
<class>line-rateline-rate<lines>$$\text{cov}(m) = \frac{\text{命中次数>0的行数}}{\text{总行数}}$$
Cobertura中的方法名可能和源码中的不一致(异步方法、lambda表达式等),当名称不匹配时按行范围匹配。
Step 4: Calculate CRAP scores
步骤4:计算CRAP得分
For each method in scope, apply the formula:
$$\text{CRAP}(m) = \text{comp}(m)^2 \times (1 - \text{cov}(m))^3 + \text{comp}(m)$$
对范围内的每个方法应用如下公式:
$$\text{CRAP}(m) = \text{comp}(m)^2 \times (1 - \text{cov}(m))^3 + \text{comp}(m)$$
Step 5: Present results
步骤5:展示结果
Present a sorted table (highest CRAP first):
| Method | Complexity | Coverage | CRAP Score | Risk |
|---------------------------------|------------|----------|------------|----------|
| OrderService.ProcessOrder | 12 | 45% | 28.4 | High |
| OrderService.ValidateItems | 8 | 90% | 8.1 | Moderate |
| OrderService.CalculateTotal | 3 | 100% | 3.0 | Low |Include:
- Summary: total methods analyzed, how many in each risk category
- Top offenders: methods with CRAP > 30, with specific recommendations
- Quick wins: methods with high complexity but where small coverage improvements would drop the score significantly
按CRAP得分从高到低排序,展示表格:
| Method | Complexity | Coverage | CRAP Score | Risk |
|---------------------------------|------------|----------|------------|----------|
| OrderService.ProcessOrder | 12 | 45% | 28.4 | High |
| OrderService.ValidateItems | 8 | 90% | 8.1 | Moderate |
| OrderService.CalculateTotal | 3 | 100% | 3.0 | Low |包含以下内容:
- 摘要:已分析的方法总数,各风险等级的方法数量
- 最高风险项:CRAP得分>30的方法,附带具体优化建议
- 低成本优化项:复杂度高,但小幅提升覆盖率就能大幅降低得分的方法
Step 6: Provide actionable recommendations
步骤6:提供可落地的优化建议
For high-CRAP methods, suggest one or both:
- Add tests -- identify uncovered branches and suggest specific test cases
- Reduce complexity -- suggest extract-method refactoring for deeply nested logic
Calculate the coverage needed to bring a method below a CRAP threshold of 15:
$$\text{cov}_{\text{needed}} = 1 - \left(\frac{15 - \text{comp}}{\text{comp}^2}\right)^{1/3}$$
This formula only applies when comp < 15. When comp >= 15, the minimum possible CRAP score (at 100% coverage) is comp itself, which already meets or exceeds the threshold. In that case, coverage alone cannot bring the CRAP score below the threshold -- the method must be refactored to reduce its cyclomatic complexity first.
Report this as: "To bring (complexity 12) below CRAP 15, increase coverage from 45% to at least 72%." For methods where complexity alone exceeds the threshold, report: " (complexity 18) cannot reach CRAP < 15 through testing alone -- reduce complexity by extracting sub-methods."
ProcessOrderComplexMethod对高CRAP得分的方法,建议以下一种或两种优化方案:
- 补充测试——识别未覆盖的分支,建议具体的测试用例
- 降低复杂度——建议对深层嵌套的逻辑执行提取方法的重构
计算将方法CRAP得分降低到15以下所需的覆盖率:
$$\text{cov}_{\text{needed}} = 1 - \left(\frac{15 - \text{comp}}{\text{comp}^2}\right)^{1/3}$$
该公式仅适用于复杂度<15的情况。当复杂度>=15时,(覆盖率100%情况下的)最低CRAP得分等于复杂度本身,已经达到或超过阈值。这种情况下仅靠提升覆盖率无法将CRAP得分降低到阈值以下——必须先重构方法降低圈复杂度。
展示方式示例:"要将(复杂度12)的CRAP得分降到15以下,需要将覆盖率从45%提升到至少72%。" 对于复杂度本身超过阈值的方法,展示为:"(复杂度18)无法仅通过测试将CRAP降到15以下——请通过提取子方法降低复杂度。"
ProcessOrderComplexMethodValidation
校验项
- Verify that coverage data was collected successfully (Cobertura XML exists and contains data)
- Cross-check that method names in coverage data match the source code
- Confirm CRAP scores by spot-checking the formula on one method manually
- Ensure a 100%-covered method's CRAP equals its complexity exactly
- 验证覆盖率数据已成功收集(Cobertura XML存在且包含有效数据)
- 交叉核对覆盖率数据中的方法名与源代码是否匹配
- 手动抽查一个方法的公式计算结果,确认CRAP得分正确
- 确保覆盖率100%的方法CRAP得分完全等于其复杂度
Common Pitfalls
常见误区
- Stale coverage data: Always regenerate coverage before computing CRAP scores. Old coverage files will produce misleading results.
- Method name mismatches: Cobertura XML may use mangled/compiler-generated names for async methods, lambdas, or local functions. Match by line ranges when names don't align.
- Generated code: Exclude auto-generated files (e.g., ,
*.Designer.cs) from analysis unless explicitly requested.*.g.cs
- 覆盖率数据过期:计算CRAP得分前务必重新生成覆盖率数据,旧的覆盖率文件会产生误导性结果
- 方法名不匹配:Cobertura XML可能对异步方法、lambda、本地函数使用编译器生成的混淆名称,名称不匹配时按行范围匹配
- 自动生成代码:除非用户明确要求,否则排除自动生成的文件(例如、
*.Designer.cs)的分析*.g.cs