CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jeffrey Palermo [MVP]

Software management consultant and CTO, Headspring Systems

How to integrate FitNesse acceptance tests into your CC.Net build - level 300

I'm doing a lot with FitNesse lately, and it's going quite well.  Unit testing ensures that each component is doing what it is supposed to, and integration testing ensures that the components work well together.  Acceptance tests are a bit different.  They actually test that the software does what the customers think it's doing.  They test that the developer understood the business need.  They give the customer (or product manager) assurance that the system actually works.

With FitNesse, our product manager (and crew) can  use a simple wiki to exercise the system.  The developers create test Fixtures that speak in the domain language but actually exercise the system under test.  A user may type:

!|fit.ActionFixture|
|start|Emailer|
|press|SendDefaultEmail|
|check|NumEmailsSent|

This simple table is enough to actually exercise the system under test and get it to do something.  If all is well, the Emailer will send a default email.  If this test fails, it saves the company from a black eye when a user encounters the problem.

It was a little tricky to get the FitNesse test integrated with our CC.Net build.  We wanted the acceptance test to be a current status report of where we are.  When all the acceptance tests are passing, we are done.  Consequently, we didn't want failing acceptance tests to break the build.  Only NUnit tests break the build because they should _always_ be passing.  No problem.  We create a new target with some exec tasks:

<exec program="<path to TestRunner.exe>" commandline="-results <some directory>\FitNesse-Results.html <FitNesse server> <port> <TestSuite>" failonerror="false"/>

This will actually call the FitNesse server (with the wiki on it) and execute all the acceptance tests.  This will produce a file in the raw FitNesse format.  We'd like it in xml so we can incorporate it in the CC.Net build report.  Xml transforming isn't a part of the .Net port, but it is in the Java version, so we'll just use it.

<exec program="java.exe" commandline="-cp bin\fit\fitnesse.jar fitnesse.runner.FormattingOption <some directory>\FitNesse-Results.html xml <some directory>\Fit-Results.xml <FitNesse server> <port> <TestSuite>" failonerror="false"/>

This hooks into the transform logic on the FitNesse server to change our raw output file to a nice Xml format.  Now we have something that CruiseControl.Net can use for a build report and email.  We will have to make an Xsl, though.  Here's a simple Xsl that will pull out the FitNesse summary information and through it out to your CC.Net build summary:

<?xml version="1.0"?>

<xsl:stylesheet

xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:output method="html"/>

<xsl:variable name="fit.result.list" select="//testResults/result"/>

<xsl:variable name="fit.wrongpagecount" select="countU$fit.result.list/counts/wrong[text() > 0])" />

<xsl:variable name="fit.ignorespagecount" select="countU$fit.result.list/counts/ignores[text() > 0])" />

<xsl:variable name="fit.exceptionspagecount" select="countU$fit.result.list/counts/exceptions[text() > 0])" />

<xsl:variable name="fit.correctpagecount" select="countU$fit.result.list/counts[wrong/text() = 0 and exceptions/text() = 0 and ignores/text() = 0])" />

<xsl:variable name="fit.correctcount" select="//testResults/finalCounts/right"/>

<xsl:variable name="fit.failures" select="//testResults/finalCounts/wrong"/>

<xsl:variable name="fit.notrun" select="//testResults/finalCounts/ignores"/>

<xsl:variable name="fit.exceptions" select="//testResults/finalCounts/exceptions"/>

<xsl:variable name="fit.case.list" select="$fit.result.list//test-case"/>

<xsl:variable name="fit.suite.list" select="$fit.result.list//test-suite"/>

<xsl:variable name="fit.failure.list" select="$fit.case.list//failure"/>

<xsl:variable name="fit.notrun.list" select="$fit.case.list//reason"/>

<xsl:variable name="colorClass">

<xsl:choose>

<xsl:when test="$fit.exceptionspagecount > 0">fiterror</xsl:when>

<xsl:when test="$fit.ignorespagecount > 0">fitignore</xsl:when>

<xsl:when test="$fit.wrongpagecount > 0" >fitfail</xsl:when>

<xsl:otherwise>fitpass</xsl:otherwise>

</xsl:choose>

</xsl:variable>

<xsl:variable name="fit.tests.present" select="countU//testResults/result) > 0 or count(/cruisecontrol/build/buildresults//testsuite) > 0" />

<xsl:template match="/">

<xsl:choose>

<xsl:when test="$fit.tests.present">

<style>

*.fitpass{

background-color: #AAFFAA;

}

*.fitfail{

background-color: #FFAAAA;

}

*.fiterror

{

background-color: #FFFFAA;

}

*.fitignore

{

background-color: #CCCCCC;

}

*.fitheader{

border: solid 1px black;

margin: 1px;

padding: 2px;

}

*.line{

margin: 5px;

}

</style>

<div>

<div class="{$colorClass} fitheader">

<strong>FitNesse Summary -- Test Pages:</strong> <xsl:value-of select="$fit.correctpagecount"/> right, <xsl:value-of select="$fit.wrongpagecount"/> wrong,

<xsl:value-of select="$fit.ignorespagecount"/> ignored, <xsl:value-of select="$fit.exceptionspagecount"/> exceptions

<strong>Assertions:</strong> <xsl:value-of select="$fit.correctcount"/> right, <xsl:value-of select="$fit.failures"/> wrong,

<xsl:value-of select="$fit.notrun"/> ignored, <xsl:value-of select="$fit.exceptions"/> exceptions

</div>

<xsl:for-each select="$fit.result.list">

<xsl:variable name="colorClass">

<xsl:choose>

<xsl:when test="counts/exceptions > 0">fiterror</xsl:when>

<xsl:when test="counts/ignores > 0">fitignore</xsl:when>

<xsl:when test="counts/wrong > 0" >fitfail</xsl:when>

<xsl:otherwise>fitpass</xsl:otherwise>

</xsl:choose>

</xsl:variable>

<div class="line">

<span class="{$colorClass}" style="padding:2px;" ><xsl:value-of select="counts/right"/> right, <xsl:value-of select="counts/wrong"/> wrong,

<xsl:value-of select="counts/ignores"/> ignored, <xsl:value-of select="counts/exceptions"/> exceptions </span>

<span style="padding:2px;"><xsl:value-of select="relativePageName"/></span>

</div>

</xsl:for-each>

</div>

</xsl:when>

</xsl:choose>

</xsl:template>

</xsl:stylesheet>

 

Hook this Xsl into your CC.Net configuration, and that's as hard as it is!  FitNesse results "magically" show up in the build summary.  It's really a big win for visibility into the state of the software.  The build summary is now the actual status report of the software, and it's not subjective.  What does 83% actually mean?  With a list of acceptance tests to fulfill, we know exactly when we are done.


 


Published Sep 13 2005, 11:30 AM by Jeffrey Palermo
Filed under:

Comments

Robin Curry said:

# September 14, 2005 11:04 AM

Chris Gardner said:

Thanks for putting this script together. I had to tweak, though, to get it to work with CruiseControl (did not try it with CC.Net). Here are my changes. Hopefully they won't get corrupted in this post.

<?xml version="1.0"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:output method="html"/>

<xsl:variable name="fit.result.list" select="//testResults/result"/>

<xsl:variable name="fit.wrongpagecount"
select="count($fit.result.list/counts/wrong[text() > 0])" />

<xsl:variable name="fit.ignorespagecount"
select="count($fit.result.list/counts/ignores[text() > 0])" />

<xsl:variable name="fit.exceptionspagecount"
select="count($fit.result.list/counts/exceptions[text() > 0])" />

<xsl:variable name="fit.correctpagecount"
select="count($fit.result.list/counts[wrong/text() = 0 and exceptions/text() = 0 and ignores/text() = 0])" />

<xsl:variable name="fit.correctcount"
select="//testResults/finalCounts/right"/>

<xsl:variable name="fit.failures"
select="//testResults/finalCounts/wrong"/>

<xsl:variable name="fit.notrun"
select="//testResults/finalCounts/ignores"/>

<xsl:variable name="fit.exceptions"
select="//testResults/finalCounts/exceptions"/>

<xsl:variable name="fit.case.list"
select="$fit.result.list//test-case"/>

<xsl:variable name="fit.suite.list"
select="$fit.result.list//test-suite"/>

<xsl:variable name="fit.failure.list"
select="$fit.case.list//failure"/>

<xsl:variable name="fit.notrun.list"
select="$fit.case.list//reason"/>

<xsl:variable name="colorClass">
<xsl:choose>
<xsl:when test="$fit.exceptionspagecount > 0">fiterror</xsl:when>
<xsl:when test="$fit.ignorespagecount > 0">fitignore</xsl:when>
<xsl:when test="$fit.wrongpagecount > 0" >fitfail</xsl:when>
<xsl:otherwise>fitpass</xsl:otherwise>
</xsl:choose>
</xsl:variable>

<xsl:variable name="fit.tests.present"
select="count($fit.result.list) > 0 or count(//cruisecontrol/build/buildresults//testsuite) > 0" />

<xsl:template match="/" mode="fitnesse">
<xsl:choose>

<xsl:when test="$fit.tests.present">
<style>

*.fitpass{

background-color: #AAFFAA;

}

*.fitfail{

background-color: #FFAAAA;

}

*.fiterror

{

background-color: #FFFFAA;

}

*.fitignore

{

background-color: #CCCCCC;

}

*.fitheader{

border: solid 1px black;

margin: 1px;

padding: 2px;

}

*.line{

margin: 5px;

}

</style>

<div>

<div class="{$colorClass} fitheader">

<strong>FitNesse Summary -- Test Pages:</strong> <xsl:value-of select="$fit.correctpagecount"/> right, <xsl:value-of select="$fit.wrongpagecount"/> wrong,

<xsl:value-of select="$fit.ignorespagecount"/> ignored, <xsl:value-of select="$fit.exceptionspagecount"/> exceptions

<strong>Assertions:</strong> <xsl:value-of select="$fit.correctcount"/> right, <xsl:value-of select="$fit.failures"/> wrong,

<xsl:value-of select="$fit.notrun"/> ignored, <xsl:value-of select="$fit.exceptions"/> exceptions

</div>

<xsl:for-each select="$fit.result.list">

<xsl:variable name="colorClass">

<xsl:choose>

<xsl:when test="counts/exceptions > 0">fiterror</xsl:when>

<xsl:when test="counts/ignores > 0">fitignore</xsl:when>

<xsl:when test="counts/wrong > 0" >fitfail</xsl:when>

<xsl:otherwise>fitpass</xsl:otherwise>

</xsl:choose>

</xsl:variable>

<div class="line">

<span class="{$colorClass}" style="padding:2px;" ><xsl:value-of select="counts/right"/> right, <xsl:value-of select="counts/wrong"/> wrong,

<xsl:value-of select="counts/ignores"/> ignored, <xsl:value-of select="counts/exceptions"/> exceptions </span>

<span style="padding:2px;"><xsl:value-of select="relativePageName"/></span>

</div>

</xsl:for-each>

</div>

</xsl:when>

</xsl:choose>

</xsl:template>

</xsl:stylesheet>
# September 16, 2005 6:13 PM

Bernard Vander Beken said:

Thanks for this info.

What is the approach you use to keep the Fitnesse server running? Do you run it in its default mode, or do you run it as a service?
# September 20, 2005 10:32 AM

Jeffrey Palermo said:

We started out running it manually, but now we've integrated it with ServiceAny that allows any command to be run as a service. Another option we considered was using the Windows scheduler to ensure that it is always running.
# September 20, 2005 1:51 PM

Jeffrey Palermo said:

A while back, I posted about how my team integrated and versioned our FitNesse wiki with CruiseControl.Net...
# December 29, 2005 2:32 PM

Jeffrey Palermo said:

Sam Gentile reminds us of the value of FIT when requirements might be vague _and_ complicated.&amp;nbsp;...
# February 23, 2006 9:20 AM

Jeffrey Palermo said:

Sam Gentile reminds us of the value of FIT when requirements might be vague _and_ complicated.&amp;nbsp;...
# March 2, 2006 10:23 AM

Jeffrey Palermo said:

A while back, I posted about how my team integrated and versioned our FitNesse wiki with CruiseControl.Net...
# March 2, 2006 10:26 AM

Jeremy D. Miller -- The Shade Tree Developer said:

The Agile development community has struggled for years with an array of solutions for automated testing...
# May 14, 2006 11:52 PM

Ruslan Trifonov's blog said:

I&#39;m digging lately with my team into our new product. We are using a full stack of buzz words in

# September 21, 2006 5:39 PM

TestingGeek said:

That's quite nice.. looks like I have got all the material that I needed to integrate FitNesse test suite with Version Control and Cruise Control.. Thanks a bunch.

# August 9, 2007 10:14 AM

Power Boots said:

Hi Jeffrey, as always, thinks are not crystal clear.

What do you mean by "Hook this Xsl into your CC.Net configuration"?

CC.net 1.3 already comes with fitnesse.xsl and fit.xsl.

And I still cannot see the Fitnesse summary into CruiseControl dashboard...

Anyhow, you did a great job!

# October 30, 2007 5:18 PM

Chandu said:

Hi All,

Can anyone please tell me how to convert the Fitnesse output to HTML format??

Thanks in Advance.

Chandu.

# March 17, 2008 11:54 AM

About Jeffrey Palermo

Jeffrey Palermo is a software management consultant and the CTO of Headspring Systems in Austin, TX. Jeffrey specializes in Agile coaching and helps companies double the productivity of software teams. Jeffrey is an MCSD.Net , Microsoft MVP, Certified Scrummaster, Austin .Net User Group leader, AgileAustin board member, INETA speaker, INETA Membership Mentor, Christian, husband, father, motorcyclist, Eagle Scout, U.S. Army Veteran, and Texas A&M University graduate. Check out Devlicio.us!

This Blog

Syndication