Thursday, September 10, 2009

Executing PartCover from NAnt

I wanted to replace NCover with PartCover. PartCover is a new code coverage tool, and its still a freeware.

With NCover I had to run NUnit twice, first to get the unit test results, and then another run to get the code coverage. (At least with the last freeware version of NCover, 1.5.8. I have not tried the commercial versions)

With PartCover its possible to run the tests AND get the coverage at the same time.

Another advantage is that I can use newer versions of NUnit. The NCover 1.5.8 does not work with NUnit from version 2.5.

It seemed rather easy, but I had problems with quotes in the NAnt build file. The PartCover always terminated with an exception, whatever I tried; quotes, variables, expressions:

Invalid option '--target=C:\Program Files\NUnit 2.4.5\bin\nunit-console.exe'

One work-around is to use a NUnit or PartCover configuration file, but I wanted the NAnt build file to be independent.

The solution was to use HTML character entity references, i.e. a double quote (“) can be written as ".

Example of NAnt target that executes PartCover which in turn produces both a coverage report and a unit test report in a specified folder:

  <target name="unitTest">

    <!-- Get all unit test assemblies -->
    <foreach item="File" property="filename">
      <in>
        <items basedir=".">
          <include name="${Build.Output}\bin\${MyProject}.Test.dll"></include>
          <include name="${Build.Output}\bin\${MyProject}.*.Test.dll"></include>
        </items>
      </in>
      <do>

        <echo message="Unittesting ${filename}"/>

        <exec program="${PartCoverHome}\Partcover.exe" failonerror="true">
          <arg line="--target &quot;${NUnitExePath}&quot;" />
          <arg line="--target-work-dir ${Build.Output}\bin"/>
          <arg line="--target-args &quot;${filename} /xml=${Build.Reports}\${path::get-file-name-without-extension(filename)}-UnitTest.xml&quot;" />
          <arg line="--include [${MyProject}.*]*" />
          <arg line="--exclude [${MyProject}.*Test*]*" />
          <arg line="--output ${Build.Reports}\${path::get-file-name-without-extension(filename)}-Coverage.xml" />
        </exec>
      </do>
    </foreach>
  </target>