I am trying to process my .coveragexml file (after converting the .coverage file) that I get after using MSTest from the command line but Sonar Runner keeps failing as it tries to parse the file. The errors consist of parsing errors such as an unexpected '?' as well as not being able to find the tag in the file.
I have tried a few ways to get the .coveragexml file: using the "vsinstr -coverage ..." and "start vsperfmon -coverage ..." commands (then running MSTest) from the command line, changing the .testrunconfig file and indicating which dlls I want to get coverage for, and tried using "CodeCoverage.exe collect ...". The first two have given me success on getting code coverage data, but I have had issues getting "CodeCoverage.exe collect ..." to collect results. Even though I can get collect code coverage results from the first two, the .coveragexml file that is produced does not seem to be in the right format that SonarQube accepts, even though they indicate on their VB.NET plugin webpage that they support MSTest and VSTest XML code coverage files. I have tried using VSTest and can get my .coveragexml files to be accepted by Sonarqube without any errors just fine. The problem is that the company I am interning for uses MSTest to run all of their unit tests, so I need to get .coveragexml data from using MSTest.
Another thing I noticed was that when I try to export the .coverage file as a .coveragexml within Visual Studio (for both MSTest or VSTest), it produces a .coveragexml format that Sonarqube doesn't accept (it just errors out due to the errors I mentioned above). When I use the "CodeCoverage.exe analyze ..." command to convert the .coverage file from VSTest, it produces a .coveragexml format that Sonarqube accepts as I receive no errors and can see my code coverage results on the dashboard. Now when I try to use "CodeCoverage.exe analyze ..." command to convert the .coverage file from MSTest, nothing happens. No .coveragexml file is produced and no errors or any sort of feedback is given. I have also tried writing a C# method to convert the .coverage file to a .coveragexml file using Microsoft.VisualStudio.Coverage.Analysis. But it produces the same format .coveragexml file as if I were exporting it from Visual Studio.
Other things that might be helpful to know:
(SonarQube errors out) The format of the .coveragexml file after exporting it from Visual Studio is like this:
<CoverageDSPriv>
<xs:schema ...>
...
</xs:schema>
<Module>
<ModuleName>...</ModuleName>
<ImageSize>...</ImageSize>
...
<NameSpaceTable>
<BlocksCovered>...</BlocksCovered>
...
(SonarQube accepts) The format of the .coveragexml file after using "CodeCoverage.exe analyze ..." (only works with VSTest's .coverage file)
<?xml version="1.0" encoding="UTF-8" ?>
<results>
<modules>
<module name="..." path="..." id="..." block_coverage="..." line_coverage="..." blocks_covered="..." ... >
<functions>
<function id="..." token="..." name="..." type_name="..." block_coverage="..." >
...
It looks like there are two completely different schemas for this data and SonarQube is only accepting one of them, is that the case? Is there another way to convert the .coverage data to the one that SonarQube accepts?
I have created this XSLT to convert the coveragexml file in the good format.
<xsl:output method="xml" indent="yes"/>
<xsl:template match="CoverageDSPriv">
<results>
<modules>
<xsl:for-each select="Module">
<xsl:element name="module">
<xsl:attribute name="name">
<xsl:value-of select="ModuleName"/>
</xsl:attribute>
<xsl:attribute name="path">
<xsl:value-of select="ModuleName"/>
</xsl:attribute>
<xsl:attribute name="block_coverage">
<xsl:value-of select="BlocksCovered div (BlocksCovered + BlocksNotCovered) * 100"/>
</xsl:attribute>
<xsl:attribute name="line_coverage">
<xsl:value-of select="LinesCovered div (LinesCovered + LinesPartiallyCovered + LinesNotCovered) * 100"/>
</xsl:attribute>
<xsl:attribute name="blocks_covered">
<xsl:value-of select="BlocksCovered"/>
</xsl:attribute>
<xsl:attribute name="blocks_not_covered">
<xsl:value-of select="BlocksNotCovered"/>
</xsl:attribute>
<xsl:attribute name="lines_covered">
<xsl:value-of select="LinesCovered"/>
</xsl:attribute>
<xsl:attribute name="lines_partially_covered">
<xsl:value-of select="LinesPartiallyCovered"/>
</xsl:attribute>
<xsl:attribute name="lines_not_covered">
<xsl:value-of select="LinesNotCovered"/>
</xsl:attribute>
<xsl:for-each select="NamespaceTable">
<xsl:for-each select="Class">
<functions>
<xsl:for-each select="Method">
<xsl:element name="function">
<xsl:attribute name="name">
<xsl:value-of select="substring-before(MethodName, '()')"/>
</xsl:attribute>
<xsl:attribute name="type_name">
<xsl:value-of select="../ClassName"/>
</xsl:attribute>
<xsl:attribute name="block_coverage">
<xsl:value-of select="BlocksCovered div (BlocksCovered + BlocksNotCovered) * 100"/>
</xsl:attribute>
<xsl:attribute name="line_coverage">
<xsl:value-of select="LinesCovered div (LinesCovered + LinesPartiallyCovered + LinesNotCovered) * 100"/>
</xsl:attribute>
<xsl:attribute name="blocks_covered">
<xsl:value-of select="BlocksCovered"/>
</xsl:attribute>
<xsl:attribute name="blocks_not_covered">
<xsl:value-of select="BlocksNotCovered"/>
</xsl:attribute>
<xsl:attribute name="lines_covered">
<xsl:value-of select="LinesCovered"/>
</xsl:attribute>
<xsl:attribute name="lines_partially_covered">
<xsl:value-of select="LinesPartiallyCovered"/>
</xsl:attribute>
<xsl:attribute name="lines_not_covered">
<xsl:value-of select="LinesNotCovered"/>
</xsl:attribute>
<ranges>
<xsl:for-each select="Lines">
<xsl:element name="range">
<xsl:attribute name="source_id">
<xsl:value-of select="SourceFileID"/>
</xsl:attribute>
<xsl:attribute name="covered">
<xsl:choose>
<xsl:when test="Coverage=0">yes</xsl:when>
<xsl:when test="Coverage=1">partial</xsl:when>
<xsl:when test="Coverage=2">no</xsl:when>
</xsl:choose>
</xsl:attribute>
<xsl:attribute name="start_line">
<xsl:value-of select="LnStart"/>
</xsl:attribute>
<xsl:attribute name="start_column">
<xsl:value-of select="ColStart"/>
</xsl:attribute>
<xsl:attribute name="end_line">
<xsl:value-of select="LnEnd"/>
</xsl:attribute>
<xsl:attribute name="end_column">
<xsl:value-of select="ColEnd"/>
</xsl:attribute>
</xsl:element>
</xsl:for-each>
</ranges>
</xsl:element>
</xsl:for-each>
</functions>
<source_files>
<xsl:for-each select="../../../SourceFileNames">
<xsl:element name="source_file">
<xsl:attribute name="id">
<xsl:value-of select="SourceFileID"/>
</xsl:attribute>
<xsl:attribute name="path">
<xsl:value-of select="SourceFileName"/>
</xsl:attribute>
</xsl:element>
</xsl:for-each>
</source_files>
</xsl:for-each>
</xsl:for-each>
</xsl:element>
</xsl:for-each>
</modules>
</results>
</xsl:template>
I think you've perfectly described the situation: There indeed are two totally different code coverage reports, which both uses the *.coveragexml extension.
The C# and VB.NET plugin only support one of those formats at the moment, and a ticket exists to add the support for the other: https://jira.codehaus.org/browse/SONARNTEST-3
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With