DarkMatter in Cyberspace
  • Home
  • Categories
  • Tags
  • Archives

Code Metrics Management with Sonar


I added coverage test with cobertura and test the demo project built yesterday. Then I add Sonar Ant task in the ant script and saved test result into Sonar database.

The following is a standard build script(add junit-4.*.jar and cobertura.jar to $ANT_HOME/lib, in Ubuntu it is /usr/share/ant/lib):

<?xml version="1.0" encoding="UTF-8"?>
<project name="MyJavaProj" basedir="./" default="coverage_report">
    <property name="build.dir" value="${basedir}/build" />
    <target name="init">
        <delete dir="${build.dir}"/>
        <mkdir dir="${build.dir}"/>
    </target>

    <property name="src.dir" value="${basedir}/src" />
    <property name="src.class.dir" value="${build.dir}/class" />
    <target name="compile-src" depends="init">
        <mkdir dir="${src.class.dir}"/>
        <javac srcdir="${src.dir}" destdir="${src.class.dir}" encoding="UTF-8" debug="true"/>
    </target>
    <taskdef classpath="cobertura.jar" resource="tasks.properties" />
    <property name="instrumented.class.dir" value="${build.dir}/instrumented-class" />
    <property name="cobertura.data.file" value="${instrumented.class.dir}/cobertura.ser" />

    <target name="instrument" depends="compile-src">
        <cobertura-instrument datafile="${cobertura.data.file}" todir="${instrumented.class.dir}">
        <fileset dir="${src.class.dir}">
            <include name="**/*.class" />
        </fileset>
        </cobertura-instrument>
    </target>

    <property name="test.dir" value="${basedir}/test" />
    <property name="test.class.dir" value="${build.dir}/test" />
    <target name="compile-test" depends="instrument">
        <mkdir dir="${test.class.dir}"/>
        <javac srcdir="${test.dir}" destdir="${test.class.dir}">
            <classpath>
                <pathelement location="${instrumented.class.dir}"/>
                <pathelement location="${src.class.dir}"/>
            </classpath>
        </javac>
    </target>

    <property name="unittest.report.dir" value="${build.dir}/unittest_report" />
    <property name="lib.dir" value="${basedir}/lib" />
    <target name="unittest" depends="compile-test">
        <mkdir dir="${unittest.report.dir}"/>
        <junit printsummary="yes" fork="yes">
            <sysproperty key="net.sourceforge.cobertura.datafile" file="${cobertura.data.file}" />
            <classpath>
                <pathelement location="${instrumented.class.dir}"/>
                <pathelement location="${src.class.dir}"/>
                <pathelement location="${test.class.dir}"/>
                <pathelement location="${src.dir}"/>
                <path refid="lib.path"/>
            </classpath>
            <formatter type="xml"/>
            <batchtest todir="${unittest.report.dir}" haltonerror="no">
                <fileset dir="${test.dir}">
                    <include name="**/*.java" />
                </fileset>
            </batchtest>
        </junit>
    </target>

    <property name="coverage.report.dir" value="${build.dir}/coverage_report" />
    <target name="coverage-report" depends="unittest">
        <cobertura-report datafile="${cobertura.data.file}" srcdir="${src.dir}" destdir="${coverage.report.dir}" format="xml" />
    </target>

    <property name="sonar.jdbc.url" value="jdbc:h2:tcp://localhost:9092/sonar" />
    <property name="sonar.jdbc.username" value="sonar" />
    <property name="sonar.jdbc.password" value="sonar" />
    <property name="sonar.projectKey" value="com.doco.gif.MyModule" />
    <property name="sonar.projectName" value="My Unit Test Project Demo" />
    <property name="sonar.projectVersion" value="2.1" />
    <property name="sonar.language" value="java" />
    <property name="sonar.sources" value="src" />
    <property name="sonar.tests" value="test" />
    <property name="sonar.binaries" value="${src.class.dir},${test.class.dir},${build.instrument.dir}" />
    <property name="sonar.dynamicAnalysis" value="reuseReports" />
    <property name="sonar.surefire.reportsPath" value="${unittest.report.dir}" />
    <property name="sonar.core.codeCoveragePlugin" value="cobertura" />
    <property name="sonar.cobertura.reportPath" value="${coverage.report.dir}/coverage.xml" />
    <target name="sonar" depends="coverage-report">
        <taskdef uri="antlib:org.sonar.ant" resource="org/sonar/ant/antlib.xml">
            <classpath path="/usr/share/ant/lib/sonar-ant-task-2.1.jar" />
        </taskdef>
        <sonar:sonar xmlns:sonar="antlib:org.sonar.ant" />
    </target>
</project>

To run this script successfully:

  1. Build a demo java project and put this script at project root;

  2. Copy sonar-ant-task-2.1.jar and junit-4.11.jar to $ANT_HOME/lib;

  3. Start Sonar server: $SONAR_HOME/bin/sonar.sh console;

  4. Run this script: ant sonar;

Note

  • You have to add "sonar.core.codeCoveragePlugin" or coverage result can't be collected by Sonar. This is not mentioned in official documents Code Coverage by Unit Tests for Java Project;

  • Take care of the spelling: "sonar.surefire.reportsPath" while "sonar.cobertura.reportPath";

  • The "xmlns:sonar="antlib:org.sonar.ant" in "sonar:sonar" is necessary or the prefix "sonar" would be unbound;

  • If unit test results can't be collected by Sonar, try to specify "sonar.binaries" carefully as above shows;

  • The value of junit report path "sonar.surefire.reportsPath" is a directory (because there are lots of reports under this folder), while the value of cobertura report is a file, if sonar can not get junit or cobertura report, verify these settings;

  • If there are "class xxx is not accessible through the ClassLoader." in output of sonar task, there are two solutions:

  • Remove property "sonar.binaries", where Sonar will not check bytecode;

  • In case you want Sonar check bytecodes, add property "sonar.libraries" like follows:



Published

May 29, 2013

Last Updated

Nov 17, 2017

Category

Tech

Tags

  • cobertura 6
  • JUnit 10
  • not_eaten: [wordpress post] 4
  • sonar 17

Contact

  • Powered by Pelican. Theme: Elegant by Talha Mansoor