我正在使用php undercontrol和代码浏览器在每个setter / getter上报告一些CRAP索引错误,即像这样的代码
public function getFoo()
{
return $this->_foo;
}
getter / setter由单元测试覆盖,复杂性为none,因为没有if / for / switch / foreach。那么为什么我得到该代码的CRAP索引为1?
PS:自我回答可能是因为复杂性没有,但我的主要问题是每个getter / setter因为CRAP索引而生成警告所以无论如何都要告诉phpunit / php代码覆盖率使CRAP等于0表示具有0复杂度指数的函数。答案 0 :(得分:27)
最低CRAP分数为1,而不是0.这是因为CRAP的算法是
CRAP(m) = comp(m)^2 * (1 – cov(m)/100)^3 + comp(m)
并且函数的最小圈复杂度(comp)值是1。所以问题不在于phpunit,而是将CRAP为1标记为问题。
一般情况下,您希望将CRAP阈值设置在5左右,低于任何地方,您也可以使用简单的代码覆盖率指标(并且拍摄100%),因为复杂因素几乎没有影响。一个CRAP> ; = 30表示没有多少测试可以使您的方法不蹩脚。
循环复杂性一般(但有多个定义)可以手工计算:
答案 1 :(得分:1)
真的是警告吗?通常,警告的阈值设置为远高于1(可能约为30)。有一个好的SO帖子here,显示了如何计算数字。我的phpunit设置中似乎有一些硬编码值,CRAP为30。
根据Alberto Savoia,CRAP索引的创建者:
“C.R.A.P。(变更风险分析和预测)指数旨在分析和预测维持现有代码所需的工作量,痛苦和时间。”
最小CRAP编号将是具有100%覆盖率的代码的圈复杂度。这个想法是复杂代码的更改比简单代码的更改更容易产生问题。
答案 2 :(得分:0)
CRAP只是一个指标。就其本身而言,它与“一根弦多长时间?”一样有用。除了是不确定答案的问题外,它也是不确定问题的答案。
如果您知道要测量的内容,则可以将其用作复杂性的非常基本的指标。为了更多地利用它,您需要相当的经验来比较实现。之后,理想情况下,您希望在同一事物的实现之间进行比较。之后,您需要深入了解所测试的代码,如果有可能,您的洞察力要比废话还高。
越高,在可测试性(包括效率)和变更点等几个方面进行改进的可能性就越大。但是,直到分数超过8000或9000时,某些东西成为绝对CRAP的可能性才开始接近确定性。诸如处理解析后的XML文档中的节点是否具有无法以任何决定性的方式改进的功能之类的基本操作,很容易就能将复杂性提高到数百个,同时又可以完美地完成工作。
有点像花钱。对于给定的目的,您可能必须花费最少的金额。可能是一百万,也可能是一千,但是无论目的如何,我们都倾向于认为支出越高,发生过多的机会就越大。但是也许它需要很高,也许您正在购买游艇。天真地将数字压低不仅在另一个方向犯了同样的错误,而且确实很危险。由于思想上的这一灾难性错误,有71人被烧死或窒息在格伦费尔大厦,他们认为仅靠数字一个人就能取得最好的成绩。
您不应认为降低CRAP可以提高可测试性或可维护性。高CRAP通常只是报告强制性复杂性的度量。从技术上讲,您可以减少CRAP,减少数字,同时降低可测试性,可维护性和可读性。您只能通过实际改进它们来改进它们。 CRAP甚至不是改善的可靠方法。有时,CRAP在改善后可能会下降。有时可能会上升。度量标准游戏的问题在于,人们通常只是替换问题或隐藏要衡量的事物以指示复杂性。
一个常见的示例是使用映射而不是switch或if语句。我倾向于自己认真地做这件事。但是,我们忘记了正在取代复杂性。在这种情况下,我们可以拥有一个带有地图实用程序的库,该库可以维护并且可以依赖。如果您将map函数与几个if语句相比包含在内,那么总体复杂性的衡量标准就是通过屋顶。当您没有这样的实用程序可供使用时,您需要非常小心如何降低复杂性。例如,如果您尝试完全消除if语句和for循环,那么祝您好运。
如果可以提高测试速度,那么复杂的循环确实会很好地反映出来。这对于诸如在一个函数中具有两个if语句之类的情况并不重要。如果第二个所依赖的状态因第一个是否匹配而有所不同,则您必须冗余地运行第一个(4次而不是2次)。
它还根据功能时间参数给出了一些指示,您实际上需要多少测试。如果您的函数具有一个布尔参数和一个基于该布尔参数的if语句,那么您至少需要两次测试才能至少获得完整的代码覆盖率。两个布尔参数和两个if语句,然后四个或三个(取决于if嵌套)。如果在最坏的情况下在if之后添加,您可能需要测试的组合数量会增加2的幂。
这可能会产生冲突,迫使您过早地对代码进行分段,因为在运行时中您可能从未真正遇到过该问题。通常,在测试开始消耗大量资源或实际上开始变得过分笨拙之前,您通常不必担心。在这种情况下,您将不必依赖CRAP,而只需了解代码的执行和基准即可。
CRAP可能会出错,因为它对复杂性做出了相当幼稚的猜测。您正在接近它的悲观或最坏情况估计。我正在看一段CRAP很高的代码,但无法区分是if($constantInScope)etc;etc;if($constantInScope)etc;
还是if($varA)etc;etc;if($varB)etc;
。
如果单个函数在执行路径上确实具有成百上千种可能的结果,那么这可能是测试它存在问题的一个好兆头。那可能是不可避免的。相反,它可能比指示的要容易得多。圈复杂度的测量能力有限,这可能就是为什么CRAP似乎还包括覆盖范围较轻的原因。如果您对其进行了测试并获得了广泛的报道,那么按照循环复杂性的想法进行测试可能并不难,特别是要记住,有可能使仅根据执行路径就不可能进行全部测试的事情成为可能,尽管非常罕见。
一个简单的示例说明为什么CRAP没用,展开循环并用数学语句等替换if语句以减少CRAP。