question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Branch coverage differs between OpenCover and Cobertura

See original GitHub issue

Given the following class being tested and a test of the ConditionalOperator method.
The report generator gives different branch coverage for a report generated from a Cobertura file from Coverlet ( .Net Core version of files below ) to a report generated from an OpenCover file file from OpenCover ( .Net Framework version of the files below ).

public class ToTest
    {
        public string ConditionalOperator(bool isTrue)
        {
            return isTrue ? "True" : "False";
        }
        
    }

public class UnitTest1
    {
        [Fact]
        public void Test1()
        {
            var toTest = new ToTest();
            toTest.ConditionalOperator(true);
        }
    }

66.7% for Net Framework OpenCover , 50% for .NetCore Coverlet

C:\Users\tonyh\AppData\Local\FineCodeCoverage\reportGenerator>reportgenerator -targetdir:C:\Users\tonyh\Downloads\reporter_output  -reports:C:\Users\tonyh\Source\Repos\SUT\Test\bin\Debug\netcoreapp3.1\fine-code-coverage\project.coverage.xml;C:\Users\tonyh\Source\Repos\SUT\UnitTestNetFramework\bin\Debug\fine-code-coverage\project.coverage.xml
2020-12-28T16:17:43: Arguments
2020-12-28T16:17:43:  -targetdir:C:\Users\tonyh\Downloads\reporter_output
2020-12-28T16:17:43:  -reports:C:\Users\tonyh\Source\Repos\SUT\Test\bin\Debug\netcoreapp3.1\fine-code-coverage\project.coverage.xml;C:\Users\tonyh\Source\Repos\SUT\UnitTestNetFramework\bin\Debug\fine-code-coverage\project.coverage.xml
2020-12-28T16:17:43: Writing report file 'C:\Users\tonyh\Downloads\reporter_output\index.html'
2020-12-28T16:17:43: Report generation took 0.3 seconds

Cobertura

<?xml version="1.0" encoding="utf-8"?>
<coverage line-rate="1" branch-rate="0.5" version="1.9" timestamp="1609172247" lines-covered="3" lines-valid="3" branches-covered="1" branches-valid="2">
  <sources>
    <source>C:\</source>
  </sources>
  <packages>
    <package name="SUT" line-rate="1" branch-rate="0.5" complexity="2">
      <classes>
        <class name="SUT.ToTest" filename="Users\tonyh\Source\Repos\SUT\SUT\ToTest.cs" line-rate="1" branch-rate="0.5" complexity="2">
          <methods>
            <method name="ConditionalOperator" signature="(System.Boolean)" line-rate="1" branch-rate="0.5" complexity="2">
              <lines>
                <line number="28" hits="1" branch="False" />
                <line number="29" hits="1" branch="True" condition-coverage="50% (1/2)">
                  <conditions>
                    <condition number="2" type="jump" coverage="50%" />
                  </conditions>
                </line>
                <line number="30" hits="1" branch="False" />
              </lines>
            </method>
          </methods>
          <lines>
            <line number="28" hits="1" branch="False" />
            <line number="29" hits="1" branch="True" condition-coverage="50% (1/2)">
              <conditions>
                <condition number="2" type="jump" coverage="50%" />
              </conditions>
            </line>
            <line number="30" hits="1" branch="False" />
          </lines>
        </class>
      </classes>
    </package>
  </packages>
</coverage>

OpenCover

<?xml version="1.0" encoding="utf-8"?>
<CoverageSession xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Version="4.7.922.0">
  <Summary numSequencePoints="3" visitedSequencePoints="3" numBranchPoints="3" visitedBranchPoints="2" sequenceCoverage="100" branchCoverage="66.67" maxCyclomaticComplexity="3" minCyclomaticComplexity="1" maxCrapScore="3" minCrapScore="2" visitedClasses="1" numClasses="1" visitedMethods="1" numMethods="1" />
  <Modules>
    <Module hash="5B-E7-52-BD-E0-D0-91-41-A2-A5-8E-5E-07-FD-C6-38-75-C8-9E-69">
      <Summary numSequencePoints="3" visitedSequencePoints="3" numBranchPoints="3" visitedBranchPoints="2" sequenceCoverage="100" branchCoverage="66.67" maxCyclomaticComplexity="3" minCyclomaticComplexity="1" maxCrapScore="3" minCrapScore="2" visitedClasses="1" numClasses="1" visitedMethods="1" numMethods="1" />
      <ModulePath>C:\Users\tonyh\Source\Repos\SUT\UnitTestNetFramework\bin\Debug\SUTNetFramework.dll</ModulePath>
      <ModuleTime>2020-12-28T16:16:17.9590077Z</ModuleTime>
      <ModuleName>SUTNetFramework</ModuleName>
      <Files>
        <File uid="1" fullPath="C:\Users\tonyh\Source\Repos\SUT\SUTNetFramework\Class1.cs" />
      </Files>
      <Classes>
        <Class>
          <Summary numSequencePoints="3" visitedSequencePoints="3" numBranchPoints="3" visitedBranchPoints="2" sequenceCoverage="100" branchCoverage="66.67" maxCyclomaticComplexity="3" minCyclomaticComplexity="1" maxCrapScore="3" minCrapScore="2" visitedClasses="1" numClasses="1" visitedMethods="1" numMethods="1" />
          <FullName>SUTNetFramework.ToTest</FullName>
          <Methods>
            <Method visited="true" cyclomaticComplexity="3" nPathComplexity="2" sequenceCoverage="100" branchCoverage="66.67" crapScore="3" isConstructor="false" isStatic="false" isGetter="false" isSetter="false">
              <Summary numSequencePoints="3" visitedSequencePoints="3" numBranchPoints="3" visitedBranchPoints="2" sequenceCoverage="100" branchCoverage="66.67" maxCyclomaticComplexity="3" minCyclomaticComplexity="3" maxCrapScore="3" minCrapScore="3" visitedClasses="0" numClasses="0" visitedMethods="1" numMethods="1" />
              <MetadataToken>100663297</MetadataToken>
              <Name>System.String SUTNetFramework.ToTest::ConditionalOperator(System.Boolean)</Name>
              <FileRef uid="1" />
              <SequencePoints>
                <SequencePoint vc="1" uspid="1" ordinal="0" offset="0" sl="32" sc="9" el="32" ec="10" bec="0" bev="0" fileid="1" />
                <SequencePoint vc="1" uspid="2" ordinal="1" offset="1" sl="33" sc="13" el="33" ec="46" bec="2" bev="1" fileid="1" />
                <SequencePoint vc="1" uspid="3" ordinal="2" offset="19" sl="34" sc="9" el="34" ec="10" bec="0" bev="0" fileid="1" />
              </SequencePoints>
              <BranchPoints>
                <BranchPoint vc="0" uspid="4" ordinal="0" offset="2" sl="33" path="0" offsetend="4" fileid="1" />
                <BranchPoint vc="1" uspid="5" ordinal="1" offset="2" sl="33" path="1" offsetend="11" fileid="1" />
              </BranchPoints>
              <MethodPoint xsi:type="SequencePoint" vc="1" uspid="1" ordinal="0" offset="0" sl="32" sc="9" el="32" ec="10" bec="0" bev="0" fileid="1" />
            </Method>
            <Method visited="false" cyclomaticComplexity="1" nPathComplexity="0" sequenceCoverage="0" branchCoverage="0" crapScore="2" isConstructor="true" isStatic="false" isGetter="false" isSetter="false">
              <Summary numSequencePoints="0" visitedSequencePoints="0" numBranchPoints="0" visitedBranchPoints="0" sequenceCoverage="0" branchCoverage="0" maxCyclomaticComplexity="1" minCyclomaticComplexity="1" maxCrapScore="2" minCrapScore="2" visitedClasses="0" numClasses="0" visitedMethods="0" numMethods="0" />
              <MetadataToken>100663298</MetadataToken>
              <Name>System.Void SUTNetFramework.ToTest::.ctor()</Name>
              <SequencePoints />
              <BranchPoints />
              <MethodPoint vc="0" uspid="6" ordinal="0" offset="0" />
            </Method>
          </Methods>
        </Class>
      </Classes>
    </Module>
  </Modules>
</CoverageSession>

Despite OpenCover reporting numBranchPoints="3" visitedBranchPoints="2" From https://github.com/danielpalme/ReportGenerator/issues/321#issuecomment-584333807

Only “real” branches ( in OpenCover XML) are taken into account. OpenCover counts differently here, it counts one extra branch per method.

I expect the percentage to be the same for the two report types.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:8 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
tonyhallettcommented, Dec 29, 2020

The calculation-details page does not have a visible link on the wiki home page https://github.com/danielpalme/ReportGenerator/wiki

It is there in the collapsed pages section

0reactions
danielpalmecommented, Dec 29, 2020

I am surprised that you have not applied your OpenCover “correction/alignment” to the metrics table. Is this a feature that has been requested before ?

All metrics are not 100% accurate if you merge several coverage files. Therefore I decided to show them “as is”. Otherwise I would have to recalculate all of them (which is often not possible without analyzing the source code).

Read more comments on GitHub >

github_iconTop Results From Across the Web

Differences between Line and Branch coverage
Line coverage measures how many statements you took (a statement is usually a line of code, not including comments, conditionals, etc).
Read more >
Code Coverage Tutorial: Branch, Statement, Function ...
This comprehensive tutorial explains what is Code Coverage in Software Testing, why we need it, its types, benefits, and drawbacks.
Read more >
SonarQube and code coverage - Guides - Sonar Community
Since SonarQube 8.3, the code coverage for .NET projects now takes into account the branch/condition coverage in addition to the line coverage.
Read more >
.NET Core Code Coverage done right – writeabout.net
There are different options to collect code coverage in .NET Core. The default is Visual Studio (a .coverage file).
Read more >
What Is Branch Coverage and What Does It Really Tell You?
Finally, branch coverage differs from line coverage in a similar way to which it differs from statement coverage. That is, even if the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found