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!

Similar Posts from the author:

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

  • virendra

    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.

  • Ashish

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

  • Ostap

    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

    • Tihomir Turzai

      Please check out if you use the correct packages.
      The junit.framework.* packages are deprecated and the
      org.junit.* packages are being used instead.

  • Siva

    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

Comments are closed.