Beside the exception / failure information, it is almost always helpful for the developers to provide them with additional screenshot of the failed tests.
From JUnit 4.7 the @Rule annotation is introduced which can be used to extend the capabilities of JUnit. With it we can invoke a custom piece of code when a test fails or succeeds.
In this example we will capture a screenshot of a failed test.
Before showing how it is done, we should have a test class at hand. For the following example just download the selenium driver from the page http://seleniumhq.org/download/ and add the jar files to classpath.

package test;

import static org.junit.Assert.assertTrue;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverBackedSelenium;
import org.openqa.selenium.firefox.FirefoxDriver;

import com.thoughtworks.selenium.Selenium;

//This is an example for the usage of ScreenshotTestRule
public class TestWithScreenshotExample {
    //
    static WebDriver driver;
    static Selenium selenium;
    // an annotation is used for defining a new rule for Junit
    @Rule
    public ScreenshotTestRule screenshotTestRule = new ScreenshotTestRule();

    @BeforeClass
    public static void beforeClass() {
        driver = new FirefoxDriver();
        selenium = new WebDriverBackedSelenium(driver, "http://www.google.com");
    }

    @AfterClass
    public static void afterClass() {
       driver.quit();
    }

    @Test
    public void testThatSucceeds() {
        selenium.open("/");
        // some text code here
        assertTrue(selenium.isTextPresent("This test will pass"));
    }

    @Test
    public void testThatFails() {
        selenium.open("/");
        //some text code here
        assertTrue(selenium.isTextPresent("This test will fail"));
    }

    // the static driver object will be needed for capturing screenshots
	public static WebDriver getDriver() {
		return driver;
	}

The trick above is to define a new JUnit rule with @Rule annotation.
The class which is used to define the new rule needs to implement the MethodRule interface and to override the apply() function.

package test;

import java.io.File;

import org.apache.commons.io.FileUtils;
import org.junit.rules.MethodRule;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;

class ScreenshotTestRule implements MethodRule {
    public Statement apply(final Statement statement, final FrameworkMethod frameworkMethod, final Object o) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                try {
                    statement.evaluate();
                } catch (Throwable t) {
                    // exception will be thrown only when a test fails.
                    captureScreenshot(frameworkMethod.getName());
                    // rethrow to allow the failure to be reported by JUnit
                    throw t;
                  }
            }

            public void captureScreenshot(String fileName) {
                try {
//
               File screenshot =  ((TakesScreenshot)TestWithScreenshotExample.getDriver()).getScreenshotAs(OutputType.FILE);
// the screenshots can be moved to a folder for sorting               FileUtils.copyFile(screenshot, new File("./screenshot-"+fileName+".png"));
                } catch (Exception e) {
                    // No need to crash the tests if the screenshot fails
                }
            }
        };
    }
}

By overwriting the apply() function we can intervene before Junit sends out the test results, and we can insert the screenshot capturing code.
For further information on using the @Rule annotation check out: http://junit.org/junit4/javadoc/4.12/org/junit/Rule.html
Happy screenshot capturing!

Posted By Tibor Dudjik

Over 10 years of experience working as a freelancer in the fields of Project Management, Manual and Automated Software Testings, Software Development. LinkedIn Profile

    5 Responses to “Capturing screenshots of failed tests in Selenium Webdriver + JUnit4”

  1. virendra says:

    Thanks for this info. But I use selenium RC for test execution and I prepare my selenium testcases in eclipse using testNG .Can u please provide me the same for my specifications. Or if there is any minor modifications in the above code to fit selenium RC ,can u please let me know that.

  2. Ashish says:

    Hi
    it would be helpful if you can show an example of generating test report of a login failed using selenium and junit

  3. Ostap says:

    Hi,

    I have tried this example, but eclipse say that MethodRule is deprecated, I am using JUit 4.10, are their other approaches to do the same ?

    Thanks,
    Ostap

  4. Siva says:

    Hi,

    Thanks for the solution. It is working absolutely fine when I have no ErrorCollector rule applied in my test. I want to takes screenshots for every failure added in errorcollector. For example, I have 5 validations in my test and all exceptions are adding into Error collector object. Here I want to capture screenshots for all failed validations in a test. Please suggest.

    Thanks
    Siva

Leave a Reply




XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>