Showing FitNesse Test Results in Hudson

Have you tried to get your FitNesse reports into Hudson?

Although it’s simple to get an Ant task to run the tests, and fail the build, it would be nice to see the results in Hudson’s junit report.
Unfortunately FitNesse outputs it’s results in a format that Hudson doesn’t understand. But that’s OK, because it’s all XML.

I knocked together a really quick Proof of Concept xsl and ant script that allow you to run the FitNesse tests and convert the output to the Ant junit format that Hudson understands.

It’s a work in progress, but it should be enough to get you going. Watch this space.
I ran it against one suite and Hudson picked up the tests (and failure) ok.

This is the build.xml that I found on Naresh Jain’s blog about integrating FitNesse with CruiseControl, with the convert target added

<?xml version="1.0" encoding="UTF-8"?>
<project name="Acceptance_Tests-Common" default="test">
  <target name="smoke" description="Run fitnesse acceptance tests.">
    <property name="fitnesse.output.dir" value="build" />
    <property name="fitnesse.output.file" value="${fitnesse.output.dir}/fitnesse-test-results" />
    <property name="fitnesse.port" value="8765" />
    <path id="fitpath">
      <fileset dir=".">
        <include name="fit*.jar" />
        <include name="lib/fitnesse-20070619/fitnesse-20070619.jar" />
      </fileset>
    </path>
    <echo message="About to run fitnesse server" level="info" />
    <parallel>
      <daemons>
        <java classname="fitnesse.FitNesse" classpath="${toString:fitpath};${ant.home}/lib/xercesImpl.jar">
          <arg value="-p" />
          <arg value="${fitnesse.port}" />
          <arg value="-e" />
          <arg value="0" />
          <arg value="-d" />
          <arg value="content" />
          <arg value="-r" />
          <arg value="FitnesseRoot" />
        </java>
      </daemons>
      <sequential>
        <echo message="sleeping for 10 seconds to let FitNesse server start" level="info" />
        <sleep seconds="10" />
        <java classpathref="fitpath" classname="fitnesse.runner.TestRunner" fork="true" resultproperty="fit.test.failures">
          <arg value="-debug" />
          <arg value="-xml" />
          <arg value="${fitnesse.output.file}.xml" />
          <arg value="-html" />
          <arg value="${fitnesse.output.file}.html" />
          <arg value="localhost" />
          <arg value="${fitnesse.port}" />
          <arg value="UserStories.FooterStory" />
        </java>
        <replace file="${fitnesse.output.file}.html" token="<base href="http://localhost:${fitnesse.port}/"/>" />
        <echo message="Finished FIT tests: ${fit.test.failures} failures/exceptions" level="info" />
        <!--
	  <fail message="FIT test failures/exceptions: ${fit.test.failures}">
	    <condition>
	      <not>
	        <equals arg1="${fit.test.failures}" arg2="0" />
	      </not>
            </condition>
	  </fail>
	  -->
      </sequential>
    </parallel>
  </target>

  <target name="convert-fitnesse-results-to-junit">
    <xslt style="fitnesse2junit.xsl" in="build/fitnesse-test-results.xml" out="build/TEST-fitnesse.xml" />
  </target>

  <target name="test" depends="smoke, convert-fitnesse-results-to-junit" />
</project>

A slight update on the XSL. This one creates the correct nodes for exceptions and errors (although it appears to make no difference to Hudson)

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
  <xsl:element name="testsuite">
    <xsl:attribute name="tests">
      <xsl:value-of select="sum(testResults/finalCounts/*)" />
    </xsl:attribute>
    <xsl:attribute name="failures">
      <xsl:value-of select="testResults/finalCounts/wrong" />
    </xsl:attribute>
    <xsl:attribute name="disabled">
      <xsl:value-of select="testResults/finalCounts/ignores" />
    </xsl:attribute>
    <xsl:attribute name="errors">
      <xsl:value-of select="testResults/finalCounts/exceptions" />
    </xsl:attribute>
    <xsl:attribute name="name">AcceptanceTests</xsl:attribute>
  <xsl:for-each select="testResults/result">
    <xsl:element name="testcase">
      <xsl:attribute name="classname">
        <xsl:value-of select="/testResults/rootPath" />
      </xsl:attribute>
      <xsl:attribute name="name">
        <xsl:value-of select="relativePageName" />
      </xsl:attribute>
      <xsl:choose>
        <xsl:when test="counts/exceptions > 0">
          <xsl:element name="error">
            <xsl:attribute name="message">
              <xsl:value-of select="counts/exceptions" />
              <xsl:text> exceptions thrown</xsl:text>
              <xsl:if test="counts/wrong > 0">
                <xsl:text> and </xsl:text>
                <xsl:value-of select="counts/wrong" />
                <xsl:text> assertions failed</xsl:text>
              </xsl:if> 
            </xsl:attribute>
          </xsl:element>
        </xsl:when>
        <xsl:when test="counts/wrong > 0">
          <xsl:element name="failure">
            <xsl:attribute name="message">
              <xsl:value-of select="counts/wrong" />
              <xsl:text> assertions failed</xsl:text>
            </xsl:attribute>
          </xsl:element>
        </xsl:when>
      </xsl:choose>
    </xsl:element>
  </xsl:for-each>
  </xsl:element>
</xsl:template>
</xsl:stylesheet>

3 thoughts on “Showing FitNesse Test Results in Hudson”

  1. Do you have an XSL to produce an html output with the format I would see if I'd run the test from the fitnesse browser. This would be archived by hudson to assist debug / tets failure investigation.

    Glenn

  2. Unfortunately, because the HTML results are stored as CDATA in the report, there is no way using XSL to extract the results as they will always be escaped (ie. &lt;html&gt; instead of <html>)
    Older versions of FitNesse allow you to export the results as both HTML and XML, and you could archive these.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>