Tuesday, March 11, 2014

Getting the most out of Fitnesse Suites

Fitnesse offers the ability to use scripts inside tests and suites as well as use REST calls following their API. This is handy because it gives us the chance to write JavaScript hacks to improve the utility of Fitnesse.

One of the fundamental problems I have with Fitnesse is maintaining the state of tests. Often times, requirements change, and tests need updating. It's easy for Fitnesse tests to get left behind when you need to meet deliverables and updating your tests requires a great deal of effort. Luckily, the Fitnesse API has some features we can take advantage of to get a glimpse at the last execution of tests.

When writing a suite, I will create tables to put similar tests together. I start with the test name, then a description, and the current status. The script uses the test name to query the restful service, which returns the latest test result and populates the status cell based on the result.

Benefits

  • Allows to skip running the suite, which can be time consuming on the machine it is running (as well as blocking for other test suites)
  • Get immediate results for each test instead of waiting for the suite
  • Easier to navigate than the suite test page

Setbacks


  • Slows loading of the suite page because ajax calls have to be made.
  • Script is very simple that this doesn't provide much useful info, just a broad overview.

Example




To use this script in your suite, you need to make a few changes:

1. Update the ajax url parameter with your url, leading up to the suite with the following period. As long as the testnames in the first table column are valid, it will automatically populate the current status column with the last data.

JavaScript

<!--[if lt IE 7 ]> <span id="ie" class="ie6"></span> <![endif]-->
<!--[if IE 7 ]>    <span id="ie" class="ie7"></span> <![endif]-->
<!--[if IE 8 ]>    <span id="ie" class="ie8"></span> <![endif]-->
<!--[if IE 9 ]>    <span id="ie" class="ie9"></span> <![endif]-->
<!--[if (gt IE 9)|!(IE)]><!--> <span id="ie" class=""></span> <!--<![endif]-->
<script>
"use strict";
// These values count up each of the tests statuses. Display for a summary of the suite.
var passingTests = 0;
var failedTests = 0;
var exceptionTests = 0;
var ignoredTests = 0;

$( document ).ready(function() {
// For each tr that is not the first
$('table tr:not(:first-child) td:first-child').each(function() {
// get the name of the test out (from >Test Name)
var testname = $(this).text().substring(1);

// Make the rest call
$.ajax({ url: "http://yoururl.yourSuite."+testname+"?pageHistory&resultDate=latest&format=xml", cache: false, type: "GET", dataType: "xml", context: this, success: function(data) { var output = ""; //IE doesn't support innerHTML element if($("#ie").is('.ie6, .ie7, .ie8, .ie9')){ var correct = $(data).find("counts")[0].firstChild.text; var wrong = $(data).find("counts")[0].firstChild.nextSibling.text; var ignored = $(data).find("counts")[0].firstChild.nextSibling.nextSibling.text; var exception = $(data).find("counts")[0].firstChild.nextSibling.nextSibling.nextSibling.text; } else { // For everyone else - Note, you'll have to update the 
// childNodes unless you follow the same table setup I use.
var correct = $(data).find("counts")[0].childNodes[1].innerHTML; 
var wrong = $(data).find("counts")[0].childNodes[3].innerHTML;
var ignored = $(data).find("counts")[0].childNodes[5].innerHTML;
var exception = $(data).find("counts")[0].childNodes[7].innerHTML;
}

// Count all the values
output += "<span class=\"correct\">right: " + correct + "</span><br/>"; if(wrong != "0") { output += "<span class=\"wrong\">wrong: " + wrong + "</span><br/>"; $(this).closest("tr").addClass("testFailed"); } if(wrong != "0" && exception == "0"){ failedTests++; } if(ignored != "0"){ output += "<span class=\"ignored\">ignored: " + ignored + "</span><br/>"; ignoredTests++; } if(exception != "0"){ output += "<span class=\"exception\">exception: "+ exception +"</span>"; $(this).closest("tr").addClass("testException"); exceptionTests++; } if(wrong == "0" && exception == "0" && correct != "0") { passingTests++; $(this).closest("tr").addClass("testPassed"); } // Append to status td $(this).closest("td").next().next().append(output); } }); }); }); </script>

CSS

<style>
.testPassed {
background-color:#CDFECD;
}

.testFailed {
background-color:#FFCCCC;
}

.testException {
background-color:#FFFFCC;
}

.correct { 
color:green;
font-weight:bold;
}

.wrong { 
color:red;
font-weight:bold;
}

.exception { 
color:#FFCC00;
font-weight:bold;
}

.ignored { 
color:grey;
font-weight:bold;
}
</style>

2016 Update: I wrote this when I was a beginner in Javascript. The code is very hacky, because the table html is generated by Fitnesse, making it hard to grab them via jQuery. This script could be improved upon by:

  • Adding last date of test run to each test, so the user has an idea of how stale the test run is.
  • Not using this, and instead just using Jenkins to run Fitnesse suites and see results in Jenkins.
  • Adding expandables on each test row to see exception text or errors.

1 comment:

  1. Great article on the fitness guide and motivational too. This types of articles really helps the people with their bodies and how to keep them in shape

    ReplyDelete