Saturday, August 11, 2012

Getting Robot Framework Results in the Email from Jenkins

The report and log pages generated by Robot Framework are great, but it is also nice to have an executive summary of the test results. If you use the Robot Framework Plugin and Email-ext plugin for Jenkins, you can get results in the email body that look like this:

Robot Framework Results


Detailed Report
Pass Percentage: 80.0%
Test Name Status Execution Datetime
Customer
Customer.Ordering
Place Credit Card Order PASS Mon Jul 30 16:17:25 CDT 2012
Save to Wishlist PASS Mon Jul 30 16:19:42 CDT 2012
Place Paypal Order PASS Mon Jul 30 16:29:01 CDT 2012
Customer.History
View Last Order PASS Mon Jul 30 16:32:00 CDT 2012
Shipping Status FAIL Mon Jul 30 16:38:02 CDT 2012

Here is a snippet from the Groovy template that generated the above:

 <%  
 import java.text.DateFormat  
 import java.text.SimpleDateFormat  
 %>  
 <!-- Robot Framework Results -->  
 <%  
 def robotResults = false  
 def actions = build.actions // List<hudson.model.Action>  
 actions.each() { action ->  
  if( action.class.simpleName.equals("RobotBuildAction") ) { // hudson.plugins.robot.RobotBuildAction  
   robotResults = true %>  
 <p><h4>Robot Framework Results</h4></p>  
 <p><a href="${rooturl}${build.url}robot/report/report.html">Detailed Report</a></p>  
 <p>Pass Percentage: <%= action.overallPassPercentage %>%</p>  
 <table cellspacing="0" cellpadding="4" border="1" align="center">  
 <thead>  
 <tr bgcolor="#F3F3F3">  
  <td><b>Test Name</b></td>  
  <td><b>Status</b></td>  
  <td><b>Execution Datetime</b></td>  
 </tr>  
 </thead>  
 <tbody>  
 <% def suites = action.result.allSuites  
   suites.each() { suite ->   
    def currSuite = suite  
    def suiteName = currSuite.displayName  
    // ignore top 2 elements in the structure as they are placeholders  
    while (currSuite.parent != null && currSuite.parent.parent != null) {  
     currSuite = currSuite.parent  
     suiteName = currSuite.displayName + "." + suiteName  
    } %>  
 <tr><td colspan="3"><b><%= suiteName %></b></td></tr>  
 <%  DateFormat format = new SimpleDateFormat("yyyyMMdd HH:mm:ss.SS")
    def execDateTcPairs = []
    suite.caseResults.each() { tc ->  
      Date execDate = format.parse(tc.starttime)
      execDateTcPairs << [execDate, tc]
    }
    // primary sort execDate, secondary displayName
    execDateTcPairs = execDateTcPairs.sort{ a,b -> a[1].displayName <=> b[1].displayName }
    execDateTcPairs = execDateTcPairs.sort{ a,b -> a[0] <=> b[0] }
    execDateTcPairs.each() {
      def execDate = it[0]
      def tc = it[1]  %>
 <tr>  
  <td><%= tc.displayName %></td>  
  <td style="color: <%= tc.isPassed() ? "#66CC00" : "#FF3333" %>"><%= tc.isPassed() ? "PASS" : "FAIL" %></td>  
  <td><%= execDate %></td>  
 </tr>  
 <%  } // tests  
   } // suites %>  
 </tbody></table><%  
  } // robot results  
 }  
 if (!robotResults) { %>  
 <p>No Robot Framework test results found.</p>  
 <%  
 } %>  
The date conversion is there to convert the date from the format Robot uses to the Java default format, which is more familiar to us.

This is the first thing I have ever done in Groovy, and I must say it is a pleasant language to write in. I especially like how getters and setters are mapped to the Groovy concept of properties.

Happy roboting.