Occasionally my solutions include multiple test projects. And I’d like NAnt to automatically save pick up the new test projects as their added without having to modify the build script. Turns out that there are a couple of ways to do this.

Method 1

<target name="run.tests" description="Runs tests for all test projects in solution." 
  depends="compile">
  <nunit2 verbose="true" haltonfailure="false" failonerror="true">
    <formatter type="Plain" extension=".txt" usefile="true" outputdir="${out.dir}"/>
    <test haltonfailure="false">
      <assemblies>
        <include name="${solution.dir}\**\bin\${build.configuration}\*Tests.dll" />
      </assemblies>
    </test>      
  </nunit2>
</target>

This one will pick up all dlls for projects ending with the word Tests (the naming convention that all of my test projects currently follow). The down side here is that if I want to run all tests regardless of any failures, I have to set haltonfailure="true". But I have another target that depends on this one that creates test documentation based the results, and I only want that target to run if all the tests pass. So I’d have to fail the build on the first failed test, which I don’t want to do.

Method 2

My solution was iterate through the test project dlls and use an exec task to run the the nunit-console. By doing this, we can look at the result property that is returned to determine if any tests failed. If any fail, we set the "all.tests.passed" variable to false, which is used at the end of the task to determine if the build should fail or if it can safely move on to the next task.

<target name="run.tests" description="Runs tests for all test projects in solution." 
  depends="compile">
  <property name="all.tests.passed" value='true' />
  
  <foreach item="File" property="test.project">
    <in>
      <items basedir="${solution.dir}">
        <include name="**bin\${build.configuration}\*Tests.dll"/>
      </items>
    </in>
    <do>
      <exec program="${nunit.exe.dir}\nunit-console.exe"         
        commandline="${doublequotes}${test.project}${doublequotes} 
        /xml=${doublequotes}${out.dir}/${path::get-file-name(test.project)}-Results.xml${doublequotes}" 
        workingdir="." failonerror="false" resultproperty="test.result" /> 
      
      <if test="${int::parse(test.result) != 0}">
        <property name="all.tests.passed" value='false' />
      </if>
    </do>
  </foreach>

  <fail message="Failure reported in one or more unit tests." 
    unless="${all.tests.passed == 'true'}" />
</target>
DotNetKicks Image