javaxmlclover

OpenClover Parsing the XML output. Java


So I recently installed OpenClover and want to parse the outputted XML file. My goal is to obtain coverage information and place that information in a Java class.

Web output from OpenClover

The imagine above shows exactly what I want to do. That is In my class Calculator I have a method "sum" I want to know that the Test testSum that exist in the class Test covered the method "sum".

The problem is that looking at the XML output from OpenClover I'm not sure how to make this connection.

Here is the XML output:

<?xml version="1.0" encoding="UTF-8"?>
<coverage generated="1586952302126" clover="4.4.1">
   <project name="OpenCloverTest 1.0-SNAPSHOT" timestamp="1586952298327">
      <metrics coveredelements="8" complexity="5" loc="24" methods="4" classes="2" statements="11" packages="1" coveredconditionals="2" coveredmethods="2" elements="17" ncloc="24" files="2" conditionals="2" coveredstatements="4"/>
      <package name="default-pkg">
         <metrics coveredelements="8" complexity="5" loc="24" methods="4" classes="2" statements="11" coveredconditionals="2" coveredmethods="2" elements="17" ncloc="24" files="2" conditionals="2" coveredstatements="4"/>
         <file path="F:\MyProj\Projects\OpenCloverTest\src\main\java\Calculator.java" name="Calculator.java">
            <metrics coveredelements="8" coveredconditionals="2" complexity="4" loc="17" coveredmethods="2" methods="3" elements="13" classes="1" ncloc="17" statements="8" conditionals="2" coveredstatements="4"/>
            <class name="Calculator">
               <metrics coveredelements="8" coveredconditionals="2" complexity="4" coveredmethods="2" methods="3" elements="13" statements="8" conditionals="2" coveredstatements="4"/>
            </class>
            <line complexity="2" visibility="public" signature="sum(int,int) : int" num="2" count="2" type="method"/>
            <line num="3" count="2" type="stmt"/>
            <line falsecount="1" truecount="1" num="3" type="cond"/>
            <line num="4" count="1" type="stmt"/>
            <line num="6" count="1" type="stmt"/>
            <line complexity="1" visibility="public" signature="mulitpliy(int,int) : int" num="8" count="1" type="method"/>
            <line num="9" count="1" type="stmt"/>
            <line complexity="1" visibility="public" signature="division(int,int) : int" num="11" count="0" type="method"/>
            <line num="12" count="0" type="stmt"/>
            <line num="13" count="0" type="stmt"/>
            <line num="14" count="0" type="stmt"/>
            <line num="15" count="0" type="stmt"/>
         </file>
         <file path="F:\MyProj\Projects\OpenCloverTest\src\main\java\OpenClover.java" name="OpenClover.java">
            <metrics coveredelements="0" coveredconditionals="0" complexity="1" loc="7" coveredmethods="0" methods="1" elements="4" classes="1" ncloc="7" statements="3" conditionals="0" coveredstatements="0"/>
            <class name="OpenClover">
               <metrics coveredelements="0" coveredconditionals="0" complexity="1" coveredmethods="0" methods="1" elements="4" statements="3" conditionals="0" coveredstatements="0"/>
            </class>
            <line complexity="1" visibility="public" signature="main(String[]) : void" num="2" count="0" type="method"/>
            <line num="3" count="0" type="stmt"/>
            <line num="4" count="0" type="stmt"/>
            <line num="5" count="0" type="stmt"/>
         </file>
      </package>
   </project>
   <testproject name="OpenCloverTest 1.0-SNAPSHOT" timestamp="1586952298327">
      <metrics coveredelements="5" complexity="2" loc="16" methods="2" classes="1" statements="3" packages="1" coveredconditionals="0" coveredmethods="2" elements="5" ncloc="14" files="1" conditionals="0" coveredstatements="3"/>
      <package name="default-pkg">
         <metrics coveredelements="5" complexity="2" loc="16" methods="2" classes="1" statements="3" coveredconditionals="0" coveredmethods="2" elements="5" ncloc="14" files="1" conditionals="0" coveredstatements="3"/>
         <file path="F:MyProj\Projects\OpenCloverTest\src\test\java\Test.java" name="Test.java">
            <metrics coveredelements="5" coveredconditionals="0" complexity="2" loc="16" coveredmethods="2" methods="2" elements="5" classes="1" ncloc="14" statements="3" conditionals="0" coveredstatements="3"/>
            <class name="Test">
               <metrics coveredelements="5" complexity="2" methods="2" testruns="2" statements="3" coveredconditionals="0" coveredmethods="2" elements="5" testfailures="0" testduration="0.008" conditionals="0" coveredstatements="3" testpasses="2"/>
            </class>
            <line complexity="1" visibility="public" signature="testSum() : void" num="6" testsuccess="true" count="1" testduration="0.008" type="method"/>
            <line num="9" count="1" type="stmt"/>
            <line num="10" count="1" type="stmt"/>
            <line complexity="1" visibility="public" signature="testMulti() : void" num="12" testsuccess="true" count="1" testduration="0.0" type="method"/>
            <line num="14" count="1" type="stmt"/>
         </file>
      </package>
   </testproject>
</coverage>

So from the XML data how can I tell which test covered which method?

EDIT: Added Test.java and Calculator.java

Calculator.java

public class Calculator {
    public int sum(int a, int b){
        if(a > b) {
            return a + a + b;
        }
        return a+b;
    }
    public int mulitpliy(int a , int b){
        return a*b;
    }
    public int division(int a, int b){
        int c = a+b;
        int d = a-b;
        int f = a*d;
        return a / b;
    }
}

Test.java

import static org.junit.Assert.assertEquals;
public class Test {
    Calculator calc = new Calculator();
    @org.junit.Test
    public void testSum(){

        assertEquals(10,calc.sum(5,5));
        assertEquals(25,calc.sum(10,5));
    }
    @org.junit.Test
    public void testMulti(){
        assertEquals(10,calc.mulitpliy(5,2));
    }
}

Example output based on answer by @Hades:

Method name    :: signature="sum(int,int) : int"
Covered line   :: 6 covered by: signature="testSum() : void"
UncoveredLines :: 0

Solution

  • Unfortunately OpenClover does not print per-test coverage information in the XML report. Extracting this information from the HTML report is not easy either.

    I suggest to have a look at the SnapshotPrinter utility, it prints information for files and classes:

    https://openclover.org/doc/manual/latest/hacking--measuring-per-test-coverage-for-manual-tests.html

    As OpenClover is open-source, you could extend the SnapshotPrinter to get information for individual methods as well, see:

    https://github.com/openclover/clover/blob/c3729a8251787ea550b45260270d5cb48cb8f0f9/clover-core/src/main/java/com/atlassian/clover/optimization/SnapshotPrinter.java

    https://github.com/openclover/clover/blob/c3729a8251787ea550b45260270d5cb48cb8f0f9/clover-core/src/main/java/com/atlassian/clover/optimization/Snapshot.java

    Alternatively, you could read this information from the clover.db database directly. Please have a look at my answer to a similar question here:

    https://community.atlassian.com/t5/Clover-questions/How-to-get-clover-coverage-percentage-for-one-test-case-on-a/qaq-p/1348720#M2200

    Cheers