简体   繁体   English

PHPUnit和CRAP索引

[英]PHPUnit and C.R.A.P index

I am using php undercontrol and the code browser report some CRAP index error on every setter/getter ie code like this 我正在使用php undercontrol,并且代码浏览器在每个setter / getter上报告一些CRAP索引错误,即像这样的代码

public function getFoo()
{
    return $this->_foo;
}

The getter/setter are covered by the unit testing, the complexity is none since there is no if/for/switch/foreach. 单元测试涵盖了吸气剂/吸气剂,因为没有if / for / switch / foreach,所以复杂度没有。 so why I get a CRAP index of 1 for that code??? 那么为什么我为该代码获得1的CRAP索引呢???

PS: self answering myself might be because the complexity is none but my main issue is that every getter/setter generate a warning because of the CRAP index so is there anyway to tell phpunit/php code coverage to make the CRAP equals to 0 for function with a 0 complexity index. PS:自我回答可能是因为复杂性没有,但我的主要问题是每个获取者/设置者都会由于CRAP索引而产生警告,因此无论如何要告诉phpunit / php代码覆盖率以使功能的CRAP等于0复杂度索引为0。

The minimum CRAP score is 1, not 0. This is because the algorithm for CRAP is 最低CRAP分数是1,而不是0。这是因为CRAP的算法是

CRAP(m) = comp(m)^2 * (1 – cov(m)/100)^3 + comp(m)

and the minimum cyclomatic complexity (comp) value for a function is one. 函数的最小循环复杂度(comp)值为1。 So the problem is not in phpunit, but whatever is flagging a CRAP of 1 as a problem. 因此,问题不在phpunit中,而是将CRAP标记为1的任何问题。

In general, you want to set your CRAP threshold somewhere around 5, anywhere lower and you may as well just use a simple code coverage metric (and shoot for 100%) since the complexity factor barely weighs in. A CRAP of >= 30 means that no amount of testing can make your method not crappy. 通常,您希望将CRAP阈值设置在5左右的任何地方,并且您也可以使用简单的代码覆盖率指标(并以100%的比率进行拍摄),因为复杂度系数几乎没有考虑。CRAP> = 30意味着没有大量的测试可以使您的方法不烂。

Cyclomatic complexity can generally (but there is more than one definition) be hand calculated as: 通常可以手动计算出圈复杂度(但有多个定义):

  • add 1 point for the function call 为函数调用加1点
  • add 1 point for every loop 每个循环增加1点
  • add 1 point for every branch 每个分支加1点

CRAP is only an indicator. CRAP只是一个指标。 On it's own it's about as useful as "How long is a piece of string?" 就其本身而言,它与“一根弦多长时间?”一样有用。 except in addition to being a question with an indeterminate answer, it's also an answer with an indeterminate question. 除了是不确定答案的问题外,它也是不确定问题的答案。

If you know what it's measuring then you can use it as a very basic indicator of complexity. 如果您知道测量的内容,则可以将其用作复杂性的非常基本的指标。 To make more use of it, you need a fair bit of experience to compare implementations. 为了更多地利用它,您需要相当的经验来比较实现。 After that you ideally want comparisons between implementations of the same thing. 之后,理想情况下,您希望在同一事物的实现之间进行比较。 After that you need to know intimately about the code being tested and chances are if you do, you have better insight than the CRAP score. 之后,您需要深入了解要测试的代码,如果有可能,您比CRAP得分要有更好的洞察力。

The higher it is the higher the probability there is to improve it on a few fronts such as testability (including efficiency) and points of change. 越高,在可测试性(包括效率)和变更点等几个方面进行改进的可能性就越大。 However, it's not until scores of over 8000 or 9000 that probability of something being absolute CRAP starts to approach certainty. 但是,直到分数超过8000或9000时,某些东西成为绝对CRAP的可能性才开始接近确定性。 Something as basic as processing the nodes from a parsed XML document for a function that can't be improved in any decisive manner can easily hit complexities into the hundreds while being perfectly fine. 诸如处理解析后的XML文档中的节点是否具有无法以任何决定性的方式改进的功能之类的基本操作,可以轻松地将复杂性提高到数百个,同时又能达到完美的效果。

It's a bit like spending money. 这有点像花钱。 For a given purpose you might have to spend a minimum amount. 对于给定的目的,您可能必须花费最少的金额。 It could be a million or it could be a thousand but regardless of the purpose we tend to assume that the higher the spending the chance of it being excessive. 可能是一百万,也可能是一千,但是无论目的如何,我们都倾向于认为支出越高,发生过多的机会就越大。 But perhaps it needs to be high, perhaps you're buying a yacht. 但是也许它需要很高,也许您正在购买游艇。 Naively forcing numbers down isn't just making the same mistake in the other direction but is genuinely dangerous. 天真地将数字压低不仅在另一个方向犯了同样的错误,而且确实很危险。 71 people were burnt to death or asphyxiated in Grenfell Tower due to this catastrophic error in thinking, believing that something could be best achieved purely going by the numbers alone. 由于思维上的灾难性错误,有71人被烧死或窒息在格伦费尔大厦,他们认为仅靠数字一个人就能取得最好的成绩。

You shouldn't assume that reducing CRAP improves testability or maintainability. 您不应该认为降低CRAP可以提高可测试性或可维护性。 Quite often a high CRAP is simply reporting a measure of mandatory complexity. 高CRAP通常只是报告强制性复杂性的度量。 You can technically reduce CRAP, gaming the numbers, while decreasing testability, maintainability and readability. 从技术上讲,您可以减少CRAP,减少数字,同时降低可测试性,可维护性和可读性。 You can only improve these things by actually improving them. 您只能通过实际改进它们来改进它们。 CRAP isn't even a reliable measure of improvement. CRAP甚至不是改善的可靠方法。 Sometimes CRAP might go down after an improvement. 有时,CRAP在改善后可能会下降。 Sometimes it might go up. 有时可能会上升。 The problem is with metrics games is people often just displace the problem or hide the thing being measured as an indicator of complexity. 度量标准游戏的问题在于,人们通常只是替换问题或隐藏要衡量的事物作为复杂性的指标。

A common example is to use a map instead of a switch or if statements. 一个常见的示例是使用映射而不是switch或if语句。 I tend to do this myself religiously. 我倾向于自己认真地做这件事。 We forget however that we're displacing the complexity. 但是,我们忘记了正在取代复杂性。 In this case we can, we have a library with a map utility that's maintained and can be relied upon. 在这种情况下,我们可以拥有一个带有地图实用程序的库,该库可以维护并且可以依赖。 If you include that map function compared to a few if statements, an overall measure of complexity would be through the roof. 如果您将map函数与几个if语句相比包含在内,那么总体复杂性的衡量标准就是通过屋顶。 When you don't have such a utility at your disposal, you need to be very careful how you go about reducing complexity. 当您没有这样的实用程序可供使用时,您需要非常小心如何降低复杂性。 For example, if you go about it trying to eliminate if statements and for loops altogether, I wish you good luck with that. 例如,如果您尝试完全消除if语句和for循环,那么祝您好运。

Cyclomatic complexity does tend to reflect quite well if the speed of tests can be improved. 如果可以提高测试速度,则圈复杂度的确会很好地反映出来。 This applies trivially to cases such as having two if statements in a function. 这对于诸如在一个函数中具有两个if语句之类的情况并不重要。 If the state the second relies upon differs based on if the first matches or not then you have to run the first redundantly (4 times instead of 2). 如果第二个所依赖的状态因第一个是否匹配而有所不同,则您必须冗余地运行第一个(4次而不是2次)。 When you combine code often the possible permutations goes up non-linearly. 当您组合代码时,可能的排列会非线性地上升。 If you have eight functions that take a boolean and return a boolean then you can test each one individually to get 8 times 2 (boolean has two possible input values) tests (16 tests). 如果您有八个采用布尔值并返回布尔值的函数,则可以分别测试每个函数以得到8乘2(布尔值有两个可能的输入值)测试(16个测试)。 However if you combine all of those functions then there are 256 different possible combinations of input. 但是,如果您将所有这些功能组合在一起,那么将有256种可能的输入组合。 Cyclomatic complexity can help indicate where this might be the case. 圈复杂度可以帮助指出可能的情况。

It also gives some indication of how many tests you really need in terms of function times parameters. 它还可以根据功能时间参数来指示您真正需要多少测试。 If you have a function with one boolean parameter and one if statement based on it then you need at least two tests to get at least full code coverage. 如果您的函数具有一个布尔参数和一个基于该布尔参数的if语句,那么您至少需要两次测试才能至少获得完整的代码覆盖率。 Two boolean parameters and two if statements then either four or three depending if the ifs are nested. 两个布尔参数和两个if语句,然后四个或三个(取决于if嵌套)。 The number of combinations you might need to test increases by the power of two just for each if added after an if in the worst case. 如果在最坏的情况下在if之后添加,则可能需要测试的组合数会增加2的幂。

This can create a conflict, forcing you to fragment code prematurely, as in runtime you may never actually have that issue. 这可能会产生冲突,迫使您过早地对代码进行分段,因为在运行时中您可能从未真正遇到过该问题。 You generally shouldn't worry about that until tests start to consume a lot of resources or actually start to become disproportionately unwieldy. 通常,在测试开始消耗大量资源或实际上开始变得过分笨拙之前,您通常不必担心。 In that case you wouldn't rely on CRAP but understanding of the code's execution and benchmarks. 在那种情况下,您将不会依赖CRAP,而是会了解代码的执行和基准。

CRAP can get it wrong as it makes a fairly naive guess about complexity. CRAP可能会出错,因为它对复杂性做出了相当幼稚的猜测。 You're getting closer to a pessimistic or worst case estimate with it. 您正在接近它的悲观或最坏情况估计。 I'm looking at a piece of code that's got a high CRAP but it's not able to tell between having if($constantInScope)etc;etc;if($constantInScope)etc; 我正在看一段代码,它具有很高的CRAP,但无法分辨if($constantInScope)etc;etc;if($constantInScope)etc;if($constantInScope)etc;etc;if($constantInScope)etc; or if($varA)etc;etc;if($varB)etc; if($varA)etc;etc;if($varB)etc; .

If a single function genuinely has hundreds, thousands or millions of possible outcomes in terms of execution path then that is probably a good sign that there are issues testing it. 如果单个函数在执行路径上确实具有成百上千种可能的结果,那么这可能是测试它存在问题的一个好兆头。 that might be inescapable. 那可能是不可避免的。 Conversely, it might be far easier to test than indicated. 相反,它可能比指示的要容易得多。 The limited ability for cyclomatic complexity to measure that might be why CRAP also appears to include a counter weight of coverage. 圈复杂度的测量能力有限,这可能就是为什么CRAP似乎还包括覆盖范围较轻的原因。 If you tested it and got a lot of coverage then it probably isn't that hard to test as the cyclomatic complexity thought, especially keeping in mind that it's possible to make things impossible to fully test in terms of execution paths alone by necessity, albeit very rare. 如果您对其进行了测试并获得了广泛的报道,那么按照循环复杂性的想法进行测试可能并不难,特别是要记住,有可能使仅根据执行路径就不可能进行全部测试的事情成为可能,尽管极少。

A simple example of why CRAP is useless, unroll your loops and replace if statements with mathematical statements and the like to reduce CRAP. 一个简单的示例说明为什么CRAP没用,展开循环并用数学语句等替换if语句以减少CRAP。

Is it really a warning? 真的是警告吗? Generally the threshold for warnings is set much higher than 1 (perhaps around 30). 通常,警告的阈值设置为远高于1(可能约为30)。 There is a good SO post here that shows how the number is calculated. 这是一个很好SO张贴在这里显示的数字是如何计算的。 There seems to be a few hardcoded values in my phpunit setup for CRAP of 30. 我的phpunit设置中似乎有一些针对CRAP的硬编码值30。

According to Alberto Savoia , the creator of the CRAP index: 根据CRAP索引的创建者Alberto Savoia的说法:

"The CRAP (Change Risk Analysis and Predictions) index is designed to analyze and predict the amount of effort, pain, and time required to maintain an existing body of code." “ CRAP(变更风险分析和预测)索引旨在分析和预测维护现有代码体所需的工作量,痛苦和时间。”

The minimum CRAP number will be the cyclomatic complexity for code with 100% coverage. 最小CRAP数量将是覆盖率达到100%的代码的圈复杂度。 The idea being that changes to complex code are more likely to create problems than changes to simple code. 这样的想法是,对复杂代码的更改比对简单代码的更改更有可能产生问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM