So now that we know what the CFG is, let's see how we can get into a count,
that else part, that is missing in our example code by introducing a new
kind of coverage. Branch coverage. As usual,
I'm going to describe branch coverage in terms of test requirements and
coverage measure. So starting from test requirements. The test requirement for
branch coverage are the branches in the program. In other words,
the goal of branch coverage is to execute all of the branches in the program.
The coverage measure is defined accordingly as the number of branches
executed by my test cases over the total number of branches in the program. And
let me remind you that branches are the outgoing edges from a decision point.
Therefore, an if statement, a switch statement, a while statement.
Any note in the c of g that has got more than one outgoing edge.
Those edges are called branches. So let's look at that using our example. So
now we're looking back at our printSum example. And in addition to the code,
I also want to represent the CFG for the program. So
let's start by looking at how many branches we have in our code. Which means how
many test requirements we have. And in this case there are two decision points.
The first one that corresponds to the first if, and the second one that
corresponds to the second if. So we have one, two, three, and four branches. So
now, let's bring back our current set of test cases. We had two test cases.
The one's that, with which we achieved a 100% statement coverage. And
let's see what happens in terms of branch coverage when we run these test cases.
I start from the first one, when we execute it, we follow the code,
we get to this decision point because the predicate in the if statement is true.
We follow the true branch, therefore we get here and then,
we exit from the program. So, in this case, we covered one of the branches,
which means that we got to 25% coverage. Now when we run the second test case,
again we follow this path. We get to this, the first if and
in this case the predicate of the if is false. Therefore, we go this way.
We reach the second predicate, the second if. The result is true, so
we follow the true branch and therefore, we cover these additional two branches.
So at this point, we are at 75% branch coverage. So what
happens is that we're missing this branch. For now, the inputs that we consider,
this branch is executed. Therefore, we need to add an additional test case. And
that this case that we need, is one for which this predicate is false and this
predicate is false. The simplest possibility in this case is the test case for
which A is equal to 0 and B is equal to 0. If we execute this test case,
our execution again followed this path, follows the fourth branch here.
And in this case, because result is not less than zero either, will follow
this branch as well. And therefore, we will reach our 100% branch coverage. And
this covered the problem. Something that I would like to clarify before we
move to the next topic, is that 100% coverage does not provide any guarantee of
finding the problems in the code. All we saw so far is the fact that by
testing more thoroughly we have more chances of finding a problem in the code.
But it doesn't matter which kind of coverage we utilize, and how much
coverage we achieve. There's always a chance that we might miss something. And
I will get back to this later on in the lesson. I just mentioned the fact that
we tested more fully when we went from statement coverage to branch coverage.
What does that mean exactly? To explain that, I'm going to introduce the concept
of test criteria subsumption. One test criteria subsumes another criteria when
all the tests widths that satisfy that criteria will also satisfy the other one.
So let me show you that with statement and
branch coverage. If we identify a test width that achieves 100% branch coverage,
the same test width will also achieve, necessarily, 100% statement coverage.
That's what happened for our example, and also what happens in general,
because branch coverage is a stronger criteria than statement coverage.
There is no way to cover all the branches without covering all the statements.
It is not true that any test results satisfies statement coverage will also
satisfy branch coverage. And, in fact, we just saw a counter example.
When we look at the printSum code. We had a test where there was achieving 100%
statement coverage and was not achieving 100% branch coverage. Therefore,
in this case we have a substantial relation in this direction. Branch coverage,
subsumes statement coverage. What it also means is that normally, or in general,
it is more expensive to achieve branch coverage than achieve statement coverage,
because achieving branch coverage requires the generation of
a larger number of test cases. So what this relation means is that
branch coverage is stronger than statement coverage but also more expensive.