Allure Reporting Preview
Allure Reporting Preview
A few months ago, if you asked me what I believe about adding reporting to an automation
project, my answer was "Why do it?"
I thought that reports that show the test execution status are useless because Jenkins has
plugins that generate them. Why put any effort in creating my own if they are available out-of-
the-box?
But recently I realized that there are other types of reports that could be very useful.
All Selenium tests are created for a QA team so its testers can run them attended or
unattended for new builds with bug fixes or new features. Most of the QA people do not know
enough coding so they can just read it to find out what the code does. How can they know the
steps that a Selenium test goes through without looking in the code?
How can they see what the test does, step by step?
The answer is by using self-documenting reports for the Selenium test. This is a report that
shows all steps that a Selenium test goes through.
There is nothing out-of-the-box in Jenkins that does this so I started looking into it.
The first one creates a simple console reporter that writes to the console all steps of a
Selenium test and screenshots taken after each step.
The second does the same thing but with the log4j framework so all information is logged in
an HTML file.
selenium-training-vancouver.com Page 1
The layout of the HTML file is not great which leads to the third solution which is to extend the
TestNG HTML reports.
This third attempt is probably good enough but it requires adding code to each page class
method to be included in the final report. This is code duplication which we should try to stay
away from.
Is there a solution that can generate the self-documenting reports with no code changes?
This framework does it all for you without adding code to the page methods. You just add
annotations to all methods to be added to the final report. The screenshots are added to the
same report through a listener.
All 4 solutions are built with Java, Selenium WebDriver, TestNG and Maven.
All code is structured using page object model.
The page classes use a base page class for common page information.
The test class uses a base test class for the driver variable and test fixtures.
You can see the first solution below. It will give you an idea of the process followed for the
other 3.
The last solution is different from the first 3 because it relies not on my own code but on
another library. The last solution, the one based on the Allure framework, is the best.
The first solution is free for you. The other 3 are not.
If you want all of them (and the full code for each), please make a PAYPAL transfer of USD 12
to [email protected] including your email address. An Amazon gift card works as well.
selenium-training-vancouver.com Page 2
All solutions implement a simple test case for the Vancouver Public Library site:
selenium-training-vancouver.com Page 3
1. Create a console reporter
selenium-training-vancouver.com Page 4
The Selenium test is very straightforward:
package tests;
import pages.HomePage;
import pages.ResultsPage;
import static org.testng.Assert.assertEquals;
import org.testng.annotations.Test;
@Test
public void pagingTest() {
home.typeKeyword("java");
ResultsPage results = homePage.executeSearch();
results = results.goToNextPage();
results = results.goToNextPage();
results = results.goToNextPage();
results = results.goToPreviousPage();
The pagingTest() is part of the SeleniumTest class which extends the BaseTest class.
BaseTest class has the driver object and the setUp()/tearDown() methods to be executed
before and after each Selenium test:
selenium-training-vancouver.com Page 5
package tests;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
@BeforeMethod
public void setUp() {
System.setProperty("webdriver.chrome.driver",
"C:/Selenium/BrowserDrivers/chromedriver.exe");
driver = new ChromeDriver();
}
@AfterMethod
public void tearDown() {
driver.quit();
}
- open(): opens the site and checks that the home url is correct
- executeSearch(): executes the search by clicking the search button; returns an object of
ResultsPage class
selenium-training-vancouver.com Page 6
package pages;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
if (urlContains(URL) == false)
throw new IllegalStateException("home page is not displayed!");
}
selenium-training-vancouver.com Page 7
ResultsPage.java has the following public methods:
- goToNextPage(): goes to next page by clicking the NextPage link and waiting until the
results count changes for the next page; returns a new ResultsPage object
- goToPreviousPage(): goes to previous page by clicking the PreviousPage link and waiting
until the results count changes for the previous page; returns a new ResultsPage object
package pages;
if (urlContains(URL) == false)
throw new IllegalStateException("results page not displayed!");
}
selenium-training-vancouver.com Page 8
public int pageNumber() {
int result = 0;
if (url().indexOf("page=") == -1)
result = 1; //no page parameter in url for page 1
else {
String resultText = StringUtils.substringBetween(url(),
"page=", "&query=");
result = Integer.parseInt(resultText);
}
return result;
}
clickNext();
clickPrevious();
selenium-training-vancouver.com Page 9
private void clickNext() {
WebElement nextPageLink = explicitWait().until(
elementToBeClickable(NEXT_XPATH));
nextPageLink.click();
}
previousPageLink.click();
}
selenium-training-vancouver.com Page 10
Both HomePage and ResultsPage classes inherit from BasePage.java:
package pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import reporter.ConsoleReporter;
import reporter.CustomReporter;
selenium-training-vancouver.com Page 11
BasePage provides access to the driver and an explicit wait objects and also to page url and
title.
It is created as abstract so objects cannot be created for it. Its methods are protected so they
can only be used from classes that inherit from BasePage.
Before creating the reporter class, let's have an interface for it:
package reporter;
The CustomReporter interface defines 2 methods for logging a text and logging a text and a
screenshot. We create the interface first so any of the next reporter classes implements it. This
way, we can use any of the reporter implementations interchangeably.
selenium-training-vancouver.com Page 12
The first reporter class is very simple:
package reporter;
import org.openqa.selenium.WebDriver;
public ConsoleReporter() {
}
@Override
public void log(String... texts) {
for (String text: texts)
System.out.println(text);
}
@Override
public void logWithScreenshot(String text) {
selenium-training-vancouver.com Page 13
The class implements the 2 methods from its interface:
- log(): displays in the console all String values that it gets as parameter
- logWithScreenshot(): takes a screenshot of the current page and displays in the console
the String parameter and the screenshot path
logWithScreenshot() relies on the Screenshot.java class for taking screenshots and saving
them. Each screenshot uses the current local time as file name:
package reporter;
import java.io.File;
import java.io.IOException;
import java.time.LocalTime;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
this.fileName = LocalTime.now().toString()
.replace("-", "_").replace(":", "_").replace(".", "_")+ ".png";
}
selenium-training-vancouver.com Page 14
public void save() {
try {
File file = ((TakesScreenshot)driver).
getScreenshotAs(OutputType.FILE);
1. Add method to BasePage class for giving access to a reporter object to the page classes:
package pages;
//same as before
import reporter.ConsoleReporter;
import reporter.CustomReporter;
selenium-training-vancouver.com Page 15
Notice that the reporter() method returns a ConsoleReporter object as a CustomReporter
variable. This is possible becase ConsoleReporter implements the CustomReporter interface.
First to HomePage.java
package pages;
//same as before
reporter().logWithScreenshot("execute search");
selenium-training-vancouver.com Page 16
and then to ResultsPage.java
package pages;
//same as before
clickNext();
clickPrevious();
//same as before
selenium-training-vancouver.com Page 17
These changes add information to the report about the page class methods.
3. Create an assertion class that logs information to report and executes assertion:
package assertions;
import reporter.ConsoleReporter;
4. In the test class, use assertEquals() from the custom assertion class:
package tests;
//same as before
home.typeKeyword("java");
ResultsPage results = home.executeSearch();
results = results.goToNextPage();
results = results.goToNextPage();
results = results.goToNextPage();
results = results.goToPreviousPage();
selenium-training-vancouver.com Page 18
Running the test again shows in the console the self-documenting report:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running TestSuite
Configuring TestNG with: TestNG652Configurator
Starting ChromeDriver 2.40.565498 on port 30825
This first solution works for simple cases but what if you want to log the information to a file?
selenium-training-vancouver.com Page 19