Friday, March 22, 2013

ReportNG Enrichment With Screenshots

Having a vast number of regression tests it became obvious to our QA team that a good reporting tool for reporting the execution results was of great essence. Our first approach in reporting was to use a simple HTML reporting plug-in for TestNG, known as ReportNG. ReportNG was the obvious way to go just because of its simplicity and easiness in integration with TestNG which is our testing framework. ReportNG provided us with a html report presenting each @Test with a pass / fail state.

Although ReportNG presented an excellent solution to our reporting problems it became apparent that for debugging purposes as well as for defect evidence purposes an extension to include screenshots was needed. These screenshots should be attached to every @Test annotation which fails along with the assertion failure.

In this post I will present you how we implemented the enrichment of ReportNG with screenshots taken by using the Selenium RC api.

ReportNG was used simply by included the dependency tag in the pom.xml of our Project, as:

<dependencies>
   <dependency>
     <groupId>org.uncommons</groupId>
     <artifactId>reportng</artifactId>
     <version>${reportngVersion}</version>
     <scope>test</scope>
 <exclusions>
   <exclusion>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
   </exclusion>
 </exclusions>
    <dependency>
</dependencies>

Selenium provides a function which capture a screenshot of the current window of the browser. We depend on this and we implement a function in Java which captures the screenshot and places it in the corresponding path in the filesystem as:

public void createScreenshot(ITestResult tr) {
 String testName=parseTestCaseName(tr.getTestClass().getRealClass().getName());
 String imagePath="screenshot-" + testName + "-"
                    + (new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()))                    + ".png";
  try {
   Selenium sel = (Selenium) tr.getAttribute("selenium");
   log.info("Parameter selenium is set to :" + sel);
   if (sel != null) {
    String base64Screenshot = sel.captureEntirePageScreenshotToString("");
    byte[] decodedScreenshot = Base64.decodeBase64(base64Screenshot.getBytes());
    FileOutputStream fos = null;
    try {
     File screenShotFname = new File(currentPath,imagePath);
     fos = new FileOutputStream(screenShotFname);
     fos.write(decodedScreenshot);
     log.info("Stored screenshot in file "+screenShotFname.getAbsolutePath());
     reportLogScreenshot(screenShotFname);
    } finally {
     if (null != fos) {
      fos.close();
     }
     } else {
      log.warn("selenium object is not set, cannot get screenshot");    
      log.warn(new Exception("STACKTRACE"));
     }

    } catch (Exception e) {
     e.printStackTrace();
    }
Ok, now with this function we have the screenshot stored in the corresponding path then we need to draw it into the reportNG log,the implementation is the following:
protected void reportLogScreenshot(File file) {
      System.setProperty("org.uncommons.reportng.escape-output", "false");
  
      String absolute = file.getAbsolutePath();
      int beginIndex = absolute.indexOf(".");
      String relative = absolute.substring(beginIndex).replace(".\\","");
      String screenShot = relative.replace('\\','/');
  
  
Reporter.log("<a href=\"" + screenShot + "\"><p align=\"left\">Error screenshot at " + new Date()+ "</p>");
Reporter.log("<p><img width=\"1024\" src=\"" + file.getAbsoluteFile()  + "\" alt=\"screenshot at " + new Date()+ "\"/></p></a><br />"); 
}
HINT: By default ReportNG escape the special characters, so in order not to see the href link in the reported log instead of your screenshot you will need to disable this escaping as:
System.setProperty("org.uncommons.reportng.escape-output", "false");
Voilà, and now the report log print the capture screenshot and display it as:
ReportNG
For the above implementation to work one should encapsulate it in a TestNG listener which calls these functions when the Test fails. We intent to release the aforementioned implementation along with the listener, as part of an upcoming open source release of our testing framework called Stevia. This framework will provide

  • Selenium and WebDriver API unification: common API methods used for UI Testing, working for both Selenium and WebDriver!, with a flick of a switch 
  • Enhanced verification methods providing element highlighting both in execution and reporting phases
  • Enhanced ReportNG reporting with element highlighting and screenshot inclusion, both for Remote (Selenium Grid) and Local (Selenium RC, WebDriver) methods.
  • Technical documentation, examples, and a lot more. 


Stay tuned for the official release and corresponding download link.... 
Read More