3

I know that basically, CC can be computed as number of decision + 1. In addition, every logical operator in the condition causes CC to increase by 1. But why?

Having the code if(A || B || C) else... the control flow graph would simply be a node with two outcomes - two branches. So I always thought branch coverage is about covering the edges of the graph, branches, which would mean to the compbound condition to evaluate to TRUE and FALSE. As for the paths, the paths can only be either TRUE or FALSE, so why the CC inreases with operators if there is no other branch of code run?

user144171
  • 523
  • 5
  • 14

2 Answers2

4

Just because the programming language abstracts the branches away into a boolean expression, doesn't mean they aren't there. If you looked at what actually gets executed, it looks like this:

 +-----------+                           
 |is A true? +------------------+       
 +----+------+                  |       
      |                         |       
 +----v------+                  |       
 |is B true? +------------------+       
 +----+------+                  |       
      |                         |       
 +----v------+                  |       
 |is C true? +------------------+       
 +----+------+                  |       
      |                         |       
+-----v-------------+   +-------v------+
| Do something else |   | Do something |
+-------------------+   +--------------+

Even without short-circuit evaluation, you have a case that it increases the complexity, because there are multiple ways to choose a given path, and you have to test and maintain all of them.

Karl Bielefeldt
  • 146,727
  • 38
  • 279
  • 479
  • thanks, that makes sense, I did not know about that. What about Decision/Branch coverage, though. Is it the same? Because when I remember all these books, they always said that edges of the graph were branches of a decision, i.e. you simply need to evaluate the whole condition to both TRUE and FALSE in order to get 100% branch coverage. That would mean that for if (A || B || C), a test cases where A=true and A=false would be enough to cover both possible outputs. – user144171 Nov 12 '14 at 21:49
  • That's sufficient for 100% branch coverage, but not for 100% *condition* coverage. Those are different things. Branch coverage is not as comprehensive. – Karl Bielefeldt Nov 12 '14 at 22:03
  • But you are talking about branches depending on the conditions. I am a bit confused. E.g. SonarQube condition coverage is said to be Branch and for A && B it requires 4 cases, which is imho NOT branch coverage. – user144171 Nov 13 '14 at 07:37
2

In the example you use, there are four (4) possible paths of execution, and hence four (4) tests that must be performed. They may be enumerated as follows, where x denotes "don't care":

  • 1xx: A is true, don't care about B and C - then path
  • 01x: A is false, B is true, don't care about C - then path
  • 001: A and B are false, C is true - then path
  • 000: A, B, and C are all false - else path

(It may be easier to see if you consider the generated assembly language.)

Cyclomatic complexity is intended to give you a handle on possible number of tests you have to run.

John R. Strohm
  • 18,043
  • 5
  • 46
  • 56