1

I have seen many examples of taking screenshots during selenium tests but looks like they are all somewhat does require a lot of work.

Some examples of them are surrounding a test with try catch block and in the catch block add the code for taking screenshot. But Here we have to surround all the tests with try catch block.

Another example is using listeners only but we need to have a separate listener for each test which is really not possible when you have a lot of test cases.

So, I have done it using listeners only but only one listener for all the tests. It will take screenshots whenever the test is failed.

I am sharing it for knowledge purpose and I am ready to accept your comments or any improvements you suggest. Also please let me know if there are any mistakes with my code.

If there is any better way of taking screenshots when you have a lot of tests to run, please suggest me that.

Thank you.

Subbu
  • 217
  • 2
  • 11
  • Usefulness of screenshots on failure is questionable at best. I say that because I, just like you, started with creating screenshot for every failure - giant waste of space is all it is. It doesn't help to understand most errors. Also screenshot happens a few moments after failure and situation could be different by then. For example: test failed due to timeout not finding some element. And from screenshot looks like element is on the screen. Is it because element showed up too late (after timeout expired), or its locator is incorrect (which you can't tell from screenshot)? – timbre timbre Sep 21 '18 at 16:58
  • So a much better option is creating screenshots selectively, on some situations where it makes sense, and logging current page DOM in other situations, where that makes sense, And in some situations (e.g. driver failure, when neither screenshot, no page dom will help), your best hope is dumping entire stack trace and making sure driver log is available. – timbre timbre Sep 21 '18 at 17:05

1 Answers1

1

Here I have four kinds of files.

  1. TestNG xml
  2. TestBoxNew.java (Selenium script in the package TestNGExmaples)
    RadioButtons.java (Selenium script in another package TestNGExamples1)
  3. Initializing.java (Contains a MAP which holds the class name and driver)
  4. Listeners.java (iTestListeners interface is implemented)

TestNG xml file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite">
  <listeners>
    <listener class-name="TestNGExamples.Listeners"/>
  </listeners>
  <test thread-count="5" name="Test">
    <classes>
      <class name="TestNGExamples.TextBoxNew"/>
      <class name="TestNGExamples1.RadioButtons"/>
    </classes>
  </test> <!-- Test -->
</suite> <!-- Suite -->

The following are two scripting TextBoxNew.java and RadioButtons.java. In each of these methods I am adding the driver to the map declared in Initializing.java.

TestNGExamples.Initializing.map1.put("TestNGExamples1.RadioButtons", driver);

If the test executes successfully I am deleting it from the map before quitting the driver.

TestNGExamples.Initializing.map1.remove("TestNGExamples1.RadioButtons");

TextBoxNew.java

In this one I have four tests TextBox1(), TextBox2(), TextBox3() and TextBox4(). I am deliberately failing the first three by passing wrong first name values in findElement method. So these will produce screenshots.

package TestNGExamples;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.Test;

public class TextBoxNew {

    @Test
    public void TextBox1() throws InterruptedException{
        System.setProperty("webdriver.gecko.driver", "C:\\BrowserDrivers\\geckodriver.exe");
        WebDriver driver = new FirefoxDriver();
        TestNGExamples.Initializing.map1.put("TestNGExamples.TextBoxNew", driver);
        driver.get("file:///D:/Selenium%20Course/Java/index.html");
        //Thread.sleep(2000);
        driver.findElement(By.id("firstnam")).sendKeys("Subbu");
        TestNGExamples.Initializing.map1.remove("TestNGExamples.TextBoxNew");
        //Thread.sleep(2000);
        driver.quit();
    }

    @Test
    public void TextBox2() throws InterruptedException {
        System.setProperty("webdriver.gecko.driver", "C:\\BrowserDrivers\\geckodriver.exe");
        WebDriver driver = new FirefoxDriver();
        TestNGExamples.Initializing.map1.put("TestNGExamples.TextBoxNew", driver);
        driver.get("file:///D:/Selenium%20Course/Java/index.html");
        //Thread.sleep(2000);
        driver.findElement(By.xpath("//input[@color='re']")).sendKeys("Venkat");
        //Thread.sleep(2000);
        TestNGExamples.Initializing.map1.remove("TestNGExamples.TextBoxNew");
        driver.quit();
    }

    @Test
    public void TextBox3() throws InterruptedException {
        System.setProperty("webdriver.gecko.driver", "C:\\BrowserDrivers\\geckodriver.exe");
        WebDriver driver = new FirefoxDriver();
        TestNGExamples.Initializing.map1.put("TestNGExamples.TextBoxNew", driver);
        driver.get("file:///D:/Selenium%20Course/Java/index.html");
        //Thread.sleep(2000);
        driver.findElement(By.id("first nam")).sendKeys("Ganesh");
        //Thread.sleep(2000);
        TestNGExamples.Initializing.map1.remove("TestNGExamples.TextBoxNew");
        driver.quit();
    }

    @Test
    public void TextBox4() throws InterruptedException {
        System.setProperty("webdriver.gecko.driver", "C:\\BrowserDrivers\\geckodriver.exe");
        WebDriver driver = new FirefoxDriver();
        TestNGExamples.Initializing.map1.put("TestNGExamples.TextBoxNew", driver);
        driver.get("file:///D:/Selenium%20Course/Java/index.html");
        //Thread.sleep(2000);
        driver.findElement(By.xpath("//input[starts-with(@id,'last')]")).sendKeys("Rajesh");
        //Thread.sleep(2000);
        TestNGExamples.Initializing.map1.remove("TestNGExamples.TextBoxNew");
        driver.quit();
    }
}

RadioButtons.java

This contains five methods and I am deliberately failing the first method by passing wrong value to findElement method. This will produce one screenshot.

package TestNGExamples1;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.Test;

public class RadioButtons {
    @Test
    public static void RadioButton1() throws InterruptedException {
        System.setProperty("webdriver.gecko.driver", "C:\\BrowserDrivers\\geckodriver.exe");
        WebDriver driver = new FirefoxDriver();
        TestNGExamples.Initializing.map1.put("TestNGExamples1.RadioButtons", driver);
        driver.get("file:///D:/Selenium%20Course/Java/index.html");     
        //Thread.sleep(2000);
        driver.findElement(By.xpath("//input[@value='femal']")).click();
        Thread.sleep(2000);
        TestNGExamples.Initializing.map1.remove("TestNGExamples1.RadioButtons");
        driver.quit();
    }
    @Test
    public static void RadioButton2() throws InterruptedException {
        System.setProperty("webdriver.gecko.driver", "C:\\BrowserDrivers\\geckodriver.exe");
        WebDriver driver = new FirefoxDriver();
        TestNGExamples.Initializing.map1.put("TestNGExamples1.RadioButtons", driver);
        driver.get("file:///D:/Selenium%20Course/Java/index.html");
        //Thread.sleep(2000);
        int no_radio_buttons = driver.findElements(By.xpath("//input[@name='gender']")).size();
        System.out.println("No. of radio buttons are "+no_radio_buttons);
        Thread.sleep(2000);
        TestNGExamples.Initializing.map1.remove("TestNGExamples1.RadioButtons");
        driver.quit();
    }

    @Test
    public static void RadioButton3() throws InterruptedException {
        System.setProperty("webdriver.gecko.driver", "C:\\BrowserDrivers\\geckodriver.exe");
        WebDriver driver = new FirefoxDriver();
        TestNGExamples.Initializing.map1.put("TestNGExamples1.RadioButtons", driver);
        driver.get("file:///D:/Selenium%20Course/Java/index.html");
        //Thread.sleep(2000);
        int no_radio_buttons = driver.findElements(By.xpath("//input[@name='gender']")).size();
        System.out.println("No. of radio buttons are "+no_radio_buttons);
        for(int j=0; j<10; j++) {
            for(int i=0; i<no_radio_buttons; i++) {
                driver.findElements(By.xpath("//input[@name='gender']")).get(i).click();
            }
        }
        //Thread.sleep(2000);       
        TestNGExamples.Initializing.map1.remove("TestNGExamples1.RadioButtons");
        driver.quit();
    }

    @Test
    public static void RadioButton4() throws InterruptedException {
        System.setProperty("webdriver.gecko.driver", "C:\\BrowserDrivers\\geckodriver.exe");
        WebDriver driver = new FirefoxDriver();
        TestNGExamples.Initializing.map1.put("TestNGExamples1.RadioButtons", driver);
        driver.get("file:///D:/Selenium%20Course/Java/index.html");
        //Thread.sleep(2000);
        int no_radio_buttons = driver.findElements(By.xpath("//input[@name='gender']")).size();
        System.out.println("No. of radio buttons are "+no_radio_buttons);
        for(int i=0; i<no_radio_buttons; i++) {
            String str = driver.findElements(By.xpath("//input[@name='gender']")).get(i).getAttribute("value");
            System.out.println(str);
        }
        //Thread.sleep(2000);       
        TestNGExamples.Initializing.map1.remove("TestNGExamples1.RadioButtons");
        driver.quit();

    }

    @Test
    public static void RadioButton5() throws InterruptedException {
        System.setProperty("webdriver.gecko.driver", "C:\\BrowserDrivers\\geckodriver.exe");
        WebDriver driver = new FirefoxDriver();
        TestNGExamples.Initializing.map1.put("TestNGExamples1.RadioButtons", driver);
        driver.get("file:///D:/Selenium%20Course/Java/index.html");
        //Thread.sleep(2000);
        int no_radio_buttons = driver.findElements(By.xpath("//input[@name='gender']")).size();
        System.out.println("No. of radio buttons are "+no_radio_buttons);
        for(int i=0; i<no_radio_buttons; i++) {
            String str = driver.findElements(By.xpath("//input[@name='gender']")).get(i).getAttribute("value");
            if(str.equals("other")) {
                driver.findElements(By.xpath("//input[@name='gender']")).get(i).click();
            }
        }
        //Thread.sleep(2000);
        TestNGExamples.Initializing.map1.remove("TestNGExamples1.RadioButtons");
        driver.quit();
    }
}

Initializing.java

May be this name looks deceptive but I am just using it to create a map inside this class.

package TestNGExamples;

import java.util.HashMap;
import java.util.Map;

import org.openqa.selenium.WebDriver;

public class Initializing {
    public static Map<String, WebDriver> map1 = new HashMap<String, WebDriver>();
}

Listener.java

Now coming to the listener, I have implemented the screenshot code in onTestFailure method. First we get the packagename.classname using the line

String clname = result.getInstanceName();

We can get the driver object stored in the map of Initializing.java by the following line.

WebDriver driver = TestNGExamples.Initializing.map1.get(clname);

Get the method name also using the following line because we store the images with packagename.classname.methodname.

String mthname = result.getName();

Now take the screenshot.

File src = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
        try {
            FileUtils.copyFile(src, new File("D:\\TestNGScreenshots\\"+clname+"."+mthname+".png"));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

Finally delete the driver from the map and quit it.

TestNGExamples.Initializing.map1.remove(clname);
driver.quit();

Full Code:

package TestNGExamples;

import java.io.File;
import java.io.IOException;

import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;
import org.apache.commons.io.FileUtils;

public class Listeners implements ITestListener{

    @Override
    public void onTestStart(ITestResult result) {
        // TODO Auto-generated method stub
        System.out.println("Test Started");
    }

    @Override
    public void onTestSuccess(ITestResult result) {
        // TODO Auto-generated method stub
        System.out.println("Test Successful");
    }

    @Override
    public void onTestFailure(ITestResult result) {
        // TODO Auto-generated method stub
        String clname = result.getInstanceName();
        System.out.println("Class Name is "+clname);
        WebDriver driver = TestNGExamples.Initializing.map1.get(clname);
        String mthname = result.getName();
        System.out.println("Method Name is "+mthname);
        File src = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
        try {
            FileUtils.copyFile(src, new File("D:\\TestNGScreenshots\\"+clname+"."+mthname+".png"));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        TestNGExamples.Initializing.map1.remove(clname);
        driver.quit();
        System.out.println("Test Failed");
    }

    @Override
    public void onTestSkipped(ITestResult result) {
        // TODO Auto-generated method stub
        System.out.println("Test Skipped");
    }

    @Override
    public void onTestFailedButWithinSuccessPercentage(ITestResult result) {
        // TODO Auto-generated method stub
        System.out.println("Test failed but with in Success Percentage");
    }

    @Override
    public void onStart(ITestContext context) {
        // TODO Auto-generated method stub
        System.out.println("Test Started Beginning");
    }

    @Override
    public void onFinish(ITestContext context) {
        // TODO Auto-generated method stub
        System.out.println("Test Started Ending");
    }
}

That's all. Please let me know if you have any comments, questions or any improvements.

Failed Tests Images

Subbu
  • 217
  • 2
  • 11