How to Take Screenshots if The Selenium Script Fails

Taking a screenshot when your Selenium WebDriver script fails is a very useful technique.

It shows you the page where failure has happened.

The best way of taking the screenshot is through JUNIT rules.

 

 

bugs bunny upset

 

Incorrect Way of Taking a Screenshot

A short example will be used for our “take screenshot” discussion.

The example automates a very simple test case that

  1. opens the http://www.vpl.ca site
  2. executes a keyword search
  3. verifies that the number of results is greater than 0

 

The example uses the following classes:

  • TEST CLASS
    • the test class extends a test base class
    • it has 1 test script only
    • the test script uses page objects and assertions

 

  • TEST BASE CLASS
    • it is used for setting up and cleaning the test environment

 

  • HOME PAGE CLASS
    • it implements the user actions related to the home page (open page, search)

 

  • RESULTS PAGE CLASS
    • it implements the user actions related to results page (get results count)

 

  • SCREENSHOT CLASS
    • it takes a screenshot of the current page

 

TEST CLASS

public class HomePageTests extends TestBase{

String keyword = “java”;

 

@Test
public void searchReturnsResults() throws Exception {

HomePage homePage = new HomePage();

homePage.openIn(browser);

ResultsPage resultsPage = homePage.search(keyword);

assertTrue(resultsPage.getResultCount() > 0);

}

}

 

TEST BASE CLASS

public class TestBase {

public static WebDriver browser;

 

@BeforeClass
public static void setUp() {
browser = new Driver().get();
}

 

@AfterClass
public static void tearDown() {
browser.quit();

}

}

 

HOME PAGE CLASS

public class HomePage {

By searchTextBoxId = By.id(“globalQuery”);
By searchButtonLocator = By.xpath(“//input[@class=’search_button1′]”);

String url = “http://www.vpl.ca”;

WebDriver browserDriver;

 

public void openIn(WebDriver driver) throws Exception
{
try
{
browserDriver = driver;
browserDriver.get(url);
}
catch (Exception ex)
{
new Screenshot(browserDriver).capture(“HomePage class – openIn method”);

throw new Exception(“site cannot be loaded”);
}

}

 

public ResultsPage search(String keyword) throws Exception {

try
{
WebElement searchTextBox = browserDriver.findElement(searchTextBoxId);
searchTextBox.sendKeys(keyword);

WebElement searchButton = browserDriver.findElement(searchButtonLocator);
searchButton.click();

return new ResultsPage(browserDriver);
}
catch (Exception ex)
{
new Screenshot(browserDriver).capture(“HomePage class – search method”);

throw new Exception(“search method failed”);
}

}

}

 

RESULTS PAGE CLASS

public class ResultsPage {

By itemCountLocator = By.xpath(“//span[@class=’items_showing_count’]”);

WebDriver browserDriver;

 

public ResultsPage(WebDriver driver)
{
browserDriver = driver;
}

 

public int getResultCount() throws Exception {

int count = 0;

try
{

WebElement resultsCount = browserDriver.findElement(itemCountLocator);

String value = resultsCount.getText();

int index1 = value.indexOf(“of”) + 3;
int index2 = value.indexOf(“items”) – 1;

count = Integer.parseInt(value.substring(index1, index2));
}
catch (Exception ex)
{
new Screenshot(browserDriver).capture(“ResultsPage class – getResultCount method”);

throw new Exception(“result count cannot be determined”);
}

return count;

}
}

SCREENSHOT CLASS

public class Screenshot {

WebDriver driver;

 

public Screenshot(WebDriver driver)
{
this.driver = driver;
}

 

public void capture(String name) {

try {

new File(“src/screenshots”).mkdirs(); 
FileOutputStream out = new FileOutputStream
(“src/screenshots/” + name + “.png”);
out.write(((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES));

out.close();

}
catch (Exception e) {
}

}

}

 

The Screenshot class is responsible for taking a screenshot of the current page of the site and storing it in the /src/screenshots folder.

Each of the page object classes (HomePage, ResultsPage) uses a try/catch block for catching exceptions in each of their methods.

If an exception is caught, a screenshot of the current site page is generated in the catch() block.

 

This approach works well but it leads to a lot of duplicated code that needs to be maintained.

Each method will need to have code for taking the screenshot in the catch() block.

The more classes you have, the more of the duplicated code.

JUNIT rules offer a great way of simplifying the process of taking a screenshot in case of failures.

 

 

 

bugs-bunny

Use JUNIT Rules for Automatic Screenshot Taking

 

JUNIT  Rules allow very flexible addition or redefinition of the behavior of each test method in a test class.

Testers can reuse or extend one of the default Rules or write their own.

The rules are useful in situations when you want to build your own test automation report, when you want to take automatic screenshots, etc.

Read more about JUNIT rules here.

A very good tutorial on JUNIT rules can be found here.

 

How will JUNIT rules help with our code?

 

First,

We create a custom JUNIT rule that takes a screenshot automatically every time an exception is generated in the project:

 

public class ScreenshotTestRule implements TestRule {

WebDriver driver;

 

public ScreenshotTestRule (WebDriver driver)
{
this.driver = driver;
}

 
public Statement apply(final Statement statement, final Description description) {

return new Statement() {

@Override
public void evaluate() throws Throwable {
try {
statement.evaluate();
}

catch (Throwable t) {
new Screenshot(driver).capture(getName(description.getClassName(), description.getMethodName()));

throw t;
}
}

 

private String getName(String className, String methodName) {
return className.substring(className.lastIndexOf(“.”) + 1) + “_” + methodName;
}
};
}
}

 

Second,

We add the JUNIT rule to the test base class:

 

public class TestBase {

public static WebDriver browser;

 

@Rule
public ScreenshotTestRule screenshotTestRule = new ScreenshotTestRule(browser);

 

@BeforeClass
public static void setUp() {
browser = new Driver().get();
}

 

@AfterClass
public static void tearDown() {
browser.quit();

}

}

 

Third,

We remove the “screenshot” code from the page object classes:

public class HomePage {

By searchTextBoxId = By.id(“globalQuery”);
By searchButtonLocator = By.xpath(“//input[@class=’search_button1′]”);

String url = “http://www.vpl.ca”;

WebDriver browserDriver;

 

public void openIn(WebDriver driver) throws Exception
{
try
{
browserDriver = driver;
browserDriver.get(url);
}
catch (Exception ex)
{
throw new Exception(“site cannot be loaded”);
}

}

 

public ResultsPage search(String keyword) throws Exception {

try
{
WebElement searchTextBox = browserDriver.findElement(searchTextBoxId);
searchTextBox.sendKeys(keyword);

WebElement searchButton = browserDriver.findElement(searchButtonLocator);
searchButton.click();

return new ResultsPage(browserDriver);
}
catch (Exception ex)
{
throw new Exception(“search method failed”);
}

}

}

 

How does this work?

Every time an exception happens, the JUNIT custom rule is triggered.

The JUNIT rule generates a screenshot of the current page (the one where the exception occurs).

The screenshot is then saved in the /src/screenshot folder.

 

I hope that this article makes it clear how to take screenshots in your automation projects.

If you liked it, please share it with your friends.

 

 

bugs-bunny-thats-all-folks

 

One Comment

Leave a comment