1.3. Branch Coverage

Branch coverage is a requirement that, for each branch in the program (e.g., if statements, loops), each branch have been executed at least once during testing. (It is sometimes also described as saying that each branch condition must have been true at least once and false at least once during testing.)

Difference from Statement Coverage

How is branch coverage different from statement coverage? If you have covered every statement in

if (x > 0)
   y = x;
   y = -x;

or in

while (z > 0)

have you not covered all the branches as well?

Difference from Statement Coverage

Only difference occurs when branches are "empty":

y = x;
if (x < 0)
   y = -x;

or in

while (z-- > 0);

In these cases branch coverage would require tests in which x and z are positive. Statement coverage would not.

Example: branch coverage

How would you test this function so that every branch is covered?

template <typename T>
int seqSearch(const T list[], int listLength, T searchItem)
    int loc;

    for (loc = 0; loc < listLength; loc++)
        if (list[loc] == searchItem)
            return loc;

    return -1;

Monitoring Branch Coverage with gcov

Again, just being aware of the idea of branch coverage can help guide our tests.

  • Recognize that we want tests to cover every branch

  • But as programs get more complicated, even experienced testers do a poor job of stmt/branch coverage

    • Automatic coverage tools can help

    • gcov can report on branches taken. Just add options to the gcov command:

      gcov -b -c mainProgram 

Reading gcov Branch Info
  • gcov reports

    • Number of times each function call successfully returned

    • # of times a branch was executed (really how many times the branch condition was evaluated)

    • and # times each branch was taken

      • For branch coverage, this is the relevant figure

  • A "branch" is anything that causes the code to not continue on in straight-line fashion

    • Branch listed right after an "if" is the "branch" that jumps around the "then" part to go to the "else" part.

    • && and || operators introduce their own branches

    • Other branches may be hidden

      • Contributed by calls to inline functions

      • Or just a branch generated by the compiler's choice of code generation

Example: gcov Branch Coverage report

        -:   84:template <typename T>
        -:   85:int seqOrderedSearch(const T list[], int listLength, T searchItem)
        -:   86:{
        1:   87:    int loc = 0;
        -:   88:
        1:   89:    while (loc < listLength && list[loc] < searchItem)
branch  0 taken 0
call    1 returns 1
branch  2 taken 0
branch  3 taken 1
        -:   90:      {
    #####:   91:       ++loc;
branch  0 never executed
        -:   92:      }
        1:   93:    if (loc < listLength && list[loc] == searchItem)
branch  0 taken 0
call    1 returns 1
branch  2 taken 0
        1:   94:       return loc;
branch  0 taken 1
        -:   95:    else
    #####:   96:       return -1;
        -:   97:}