如何阅读/改进用 PHP 计算的 C.R.A.P 指数

我刚开始使用 PHPUnit 及其丰富多彩的代码覆盖报告。我知道所有的数字和百分比,除了一个: C.R.A.P 指数。有人能给我一个可靠的解释,它意味着什么,如何分析它,如何降低它?

17743 次浏览

Basically it wants to be a predictor of the risk of change for a method.

它有两个因素:

  • 方法的代码复杂度(cyclomatic complexity) ,即所述方法中存在多少决策路径: comp(m)
  • 该方法的可测试性如何(通过代码覆盖工具提供的自动化测试)。基本上,这衡量了所述代码中有多少决策是可自动测试的。

如果该方法具有100% 的覆盖率,那么变更的风险被认为仅与该方法的复杂度相当: C.R.A.P.(m) = comp(m)

如果方法覆盖率为0% ,那么在复杂度度量中,更改的风险被认为是二次多项式(理由是,如果你不能测试一个改变了的代码路径,那么破坏的风险就会增加) : C.R.A.P.(m) = comp(m)^2 + comp(m)

Hopefully this will help you.

我只是注意到我只提供了一半的答案(阅读部分)。如果你理解了索引的原理,那么改进的方法应该是非常清楚的。但是 @edorian's answer给出了一个更加清晰的解释。

简单来说就是: 编写测试,直到覆盖率接近100% ,然后重构方法以减少循环复杂度。您可以在进行测试之前尝试重构,但是根据实际方法的复杂程度,如果您不能推断(由于所涉及的复杂程度)您正在进行的更改的所有后果,您可能会引入破坏。

@ Toader Mihai 给出了一个可靠的解释。 (+ 1 from me)

如何降低:

编写不太复杂的代码或者编写更好的测试代码

更好的测试代码?

在这种情况下,这仅仅意味着: 更高的代码覆盖率,并且通常会导致编写更多的测试。

更简单的代码?

例如: 将你的方法重构成更小的方法:

// Complex
function doSomething() {
if($a) {
if($b) {
}
if($c) {
}
} else {
if($b) {
}
if($c) {
}
}
}


// 3 less complex functions
function doSomething() {
if($a) {
doA();
} else {
doNotA();
}
}


function doA() {
if($b) {
}
if($c) {
}
}


function doNotA() {
if($b) {
}
if($c) {
}
}

(只是一个小例子,你会发现更多的资源,我敢肯定)

额外资源:

首先,让我提供一些额外的资源:

创建者关于垃圾索引的博客文章

以防万一: 循环复杂度解释道.PHP _ CodeSniffer 和 PHPMD 等工具会告诉你这个数字,以防你想知道。

And while it is for you to decide what number is "ok" one often suggested number (that is a litte high imho) is a crap index of 30 resulting in a Graph like this:

alt text (You can get the .ods file here: https://www.dropbox.com/s/3bihb9thlp2fyg8/crap.ods?dl=1 )