What is a branch in code coverage for JavaScript unit testing

I use Istanbul for code coverage of unit tests in an AngularJS project. There are 4 types of coverage and they are

  • statement
  • branch
  • function

Statement, function and line are alright but i don't understand what "branch" is. What is branch?

55323 次浏览

Somewhere where the code can take more than one route, ie it branches. A couple of examples of branching statements are if/else and switch statements.

Branch coverage tracks which of those branches have been executed so you can ensure all routes are tested properly.

From Wikipedia:

Has each branch (also called DD-path) of each control structure (such as in if and case statements) been executed? For example, given an if statement, have both the true and false branches been executed? Another way of saying this is, has every edge in the program been executed?

You have to test for each control structure all the possible cases (enter/not enter in if statements, f.e., and all the cases of a switch). Branch coverage is a metric that measures (usually in percentage) how many of the total branches your tests cover.

A branch is where the runtime can choose whether it can take one path or another. Lets take the following example:

if(a) {
Foo();
}


if(b) {
Bar();
}


Yay();

When reaching the first line, it can decide if it wants to go inside the body of the if(a)-statement. Also, it can decide not to do that. At this stage, we've seen two paths already (one branch).

The next statement after that gets more interesting. It can go inside the if body and execute Bar. It can also not do that. But remember that we've already had a branch before. The result may vary if Foo was called or not.

So we end up with four possible paths:

  • Not calling Foo, not calling Bar either
  • Calling Foo, not calling Bar
  • Not calling Foo, calling Bar
  • Calling both Foo and Bar

The last Yay is always executed, no matter if Foo or Bar was called, so that doesn't count as a branch. So the code snippet above contains four paths / two branches (calling Foo() or not, calling Bar() or not).

Like other answers already have mentioned, there are numerous statements that can cause a branch (if/switch). A few, but not all, include:

  • Conditional loops (ie. while/for/do-while)
  • The break or the continue statement
  • Binary short-circuiting operators (ie. &&/||)
    • For example. Given foo && bar, if foo is false, bar doesn't have to be evaluated. Likewise for foo || bar, if foo is true, bar doesn't have to be evaluated either.
  • Default parameters (ie. function A(someVar = []) { ... })
    • This is due to the fact that a call to this method is interpreted as an if-statement. For every call to this method the parameter is checked if its undefined. If it is, the default parameter is set for someVar (for the example above). This causes a branch to exist.

The code coverage tool wants to make sure that you've tested all branches. Best would be if all paths have been tested, or even all (edge case) values, not just the branches. This, to make sure that no unwanted behavior is executed.