As a follow-up to my post on understanding coverage metric, I want to explain how you can better visualize branch coverage. One of the reasons we feature both sequence point coverage and branch coverage numbers so prominently is that they are both essential to understanding the coverage picture for your project. Sequence point coverage relates directly to your code, so by looking at the code with coverage data overlaid, it’s easy to see which specific lines of code have not been tested.
As I explained in the last article, branch coverage is a better overall metric because it scales directly with the complexity of a method and can’t be distorted by the verbosity of your code the way that sequence point coverage can. So, if branch coverage is a better metric, then why do we even look at sequence point coverage? The main reason is that branch coverage is calculated directly from the compiler generated code, and the connection between the code and what is generated by the compiler is not always clear-cut or easy to visualize.
The primary value of branch coverage is to measure how much of your program’s structure is being exercised by your tests.
The primary value of sequence point coverage is to find the lines of code which are not being executed and are contributing to a lack of coverage.
Over the past few years, we’ve had many customers ask us to explain how the branch coverage numbers were being calculated for a given method. So, we created a technique to visualize branch coverage in the left hand margin of a method in the coverage display window. Let’s dive into an example here and describe how to interpret the diagram.
First, notice at the top of the window that our branch coverage is at 62.5% with 5 of 8 segments covered. The sequence point coverage is at 47.1% with 8 of 17 sequence points covered. The balls and line segments on the left side of the screen demonstrate those metrics visually. Each green ball represents a covered sequence point, and a red diamond represents an uncovered sequence point. If you count them up, you’ll see 8 green balls and 9 red diamonds for a total of 17 sequence points. The branch segments are shown by connecting the balls and diamonds with arrows. You’ll see 8 groups on the left with 3 of them red and 5 green for a total of 8 branch segments.
The sequence point markers are usually setup on the same line where the sequence points occur to make it obvious where they are. In addition, if you hover the mouse over a sequence point marker, or the code corresponding to it, we add additional information. The branch segment will have grey arrows showing which other segments flow into it and which other segments flow out.
In the screenshot above, the mouse is hovering over the Console.WriteLine("Segment 2");
line. You will notice that on the left, that the segment containing that code is highlighted in a slightly darker shade of green. The sequence point corresponding to that point is even darker green. There are only three sequence points in that branch segment. At the top you see a single grey arrow showing that the only way to run that segment of code is to branch there from the if (second)
segment. At the bottom of the segment, there are two grey arrows showing that there are two ways to exit this segment. Depending on the value of the if (first)
test, it can either execute the Console.WriteLine("Segment 3")
segment, or it can skip past that to the end of the enclosing if
block.
Exploring the diagram with the mouse makes it easier to understand what the branching structure of a method and what the coverage data really means. Hopefully this makes it easier for you to figure out how coverage is being calculated and why a particular section of code may not be covered by your tests.
Feel free to ask questions in the comments below.