Yesterday I was asked to add some kind of reporting to our selenium test suite. I had some ideas to create a report in excel, but this all ended up in having to write a lot of code and probably reinventing the wheel. After some time using google I came across the website of Bas Dijkstra where he was reviewing ExtentReport version 1.4. Before reading the rest of my post you might want to read this post. After reading I became pretty exited about this library! Next I went to see the website of the creator of ExtentReports, ReleventCodes.com. I installed the latest version (at the time 2.04) by adding it to my maven pom.xml and gave it a go. Below my approach and some tips.

Installation:

For installation I used maven. Add the following to the pom.xml of your test project:

<dependency>
    <groupId>com.relevantcodes</groupId>
    <artifactId>extentreports</artifactId>
    <version>2.04</version>
</dependency>

Open your command prompt and navigate to where ever your pom.xml is located and execute the following command:

mvn install -DskipTests
And your ready to go!

Using Junit? Use a @Rule annotation!

Since we already developed a “complete” automation test suite I didn’t want to add a new reporting line after every test we have written. When your experimenting with this library you could do this but later on you probably want to put this on a higher level in your testsuite.
First of all I want to tell you a little about the testsuite. I’m using Selenium webdriver (Java) and I developed our suite using the PageObjectPattern. I wrote a baseTestClass and all other tests extend this class. The baseTestClass responsibility is to setup Selenium (start a browser, navigating to a URL, truncate a database, etc.) I wrote a screenshotTaker class earlier which makes a screenshot of the browser when the test fails. This screenshotTakerClass has been added as a rule to the baseTestClass. This seems like a good starting point for me to see if a test fails if it creates a report and how it looks. For now I just added a line of code to the “failed” method of this specific class:

BaseTestClass snippet:
See line 11 for the rule where we call on the screenshotTakerClass

public class BaseTestclass {

	public static WebDriver driver;	
	/*
	 * Set some properties as a member.
	*/	
	private static String screenshotLocatie;
	private static String browser;
	
	@Rule
    public ScreenshotTaker screenShootRule = new ScreenshotTaker(driver, screenshotLocatie);

	@BeforeClass
	public static void setup() throws Exception {
		getProperties();
		
		//empty the database before testing.
		resetDatabase();
		if ("Firefox".equals(browser)) {
			driver = new FirefoxDriver();
		} else if("InternetExplorer".equals(browser)) {
			driver = new InternetExplorerDriver();
		} else {
			//fallback when browser propertie is not set to firefox.
			driver = new FirefoxDriver();			
		}
		//set the browser to max size
		driver.manage().window().maximize();
	}
}

screenshotTakerClass:


public class ScreenshotTaker extends TestWatcher {
    private WebDriver browser;
    private String screenshotLocation;
	private String filenameOfReport= "C:/myReportingDir/testReport" + DateTimeHelper.getDateOfToday() + ".html";
    
    public ScreenshotTaker(WebDriver browser, String screenshotLocatie) {
        this.browser =  browser;
        this.screenshotLocation =  screenshotLocation;
    }

    @Override
    protected void failed(Throwable e, Description description) {
        TakesScreenshot takesScreenshot = (TakesScreenshot) browser;

        File scrFile = takesScreenshot.getScreenshotAs(OutputType.FILE);
        File destFile = getDestinationFile(description);
        try {
            FileUtils.copyFile(scrFile, destFile);
        } catch (IOException ioe) {
            throw new RuntimeException(ioe);
        }
        ExtentReports extent = createReport();
        ExtentTest test = extent.startTest(description.getDisplayName(), "Test failed, click here for further details");

		// step log
		test.log(LogStatus.FAIL, "Failure trace Selenium: "+ e.toString());
		flushReports(extent, test);
    }
    
    //When passed only write to the log.
    @Override
    protected void succeeded(Description description) {
		ExtentReports extent = createReport();
         ExtentTest test = extent.startTest(description.getDisplayName(), "-");

 		// step log
 		test.log(LogStatus.PASS, "-");
 		flushReports(extent, test);
    }

    private ExtentReports createReport() {
    	ExtentReports extent = new ExtentReports(filenameOfReport, false);
        extent.config().reportName("My first extentReport report");
        extent.config().reportHeadline("See my awesome passed tests!");
        return extent;
    }
    
    private void flushReports(ExtentReports extent, ExtentTest test){
    	// ending test
 		extent.endTest(test);
 		// writing everything to document
 		extent.flush();
    }
    
    private File getDestinationFile(Description description) {
        String userDirectory = screenshotLocation;
        String date = getDateTime();
        String fileName = description.getDisplayName() + "_" + date + ".png";
        //add date of today
        String dateForDir = DateTimeHelper.getDateOfToday();
        String absoluteFileName = userDirectory + "/" + dateForDir + "/" + fileName;

        return new File(absoluteFileName);
    }
    
    private String getDateTime() {
    	Date date = Calendar.getInstance().getTime();

        // Display a date in day, month, year format
        DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy_HH_mm_ss");
        String today = formatter.format(date);
        return today;
    }
}

After adding this to existing screenshotTakerClass I let JUnit run a complete test of our testsuite.
Every single test we have is added to the report, passed or failed!

Because I do not have to add a log line after every test I have to pass on the name of the test to identify the failing (or passed) test.
I came to this line (see line 23 and 34 in the code above)

ExtentTest test = extent.startTest(description.getDisplayName(), "Description of the test here....");

In the report it will show up as methodName(packageName) (for example: myAwsomeTest(com.mytestproject.seleniumtests.mostawesometests).

Next thing I wanted is to show the failure trace to see what went wrong:
I added this line:

test.log(LogStatus.FAIL, "Failure trace Selenium: "+ e.toString());

This one only applies to the failure, when a test is passed I don’t need any more information then it is passed:

test.log(LogStatus.PASS, "-");

After experimenting a little bit with ExtentReports I changed the reporting name to make it more suitable to the test project.

extent.config().reportName("Selenium - Awesome project");
extent.config().reportHeadline("Overview of testresults");

That’s it for now! After this modifications the report suited just fine for me. Only thing left is to rename the screenshotTakerClass since it now has more responsibilities.
I think EventReports is a very nice library to use when you have the need to build reports for Selenium. It will probably also fit other Java based test tools.

For more detailed information and other possibilities in Extend reports see:
http://extentreports.relevantcodes.com/2x/docs.html

Questions? Please leave a comment below!