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?
2
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.
3
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.