Can Selenium take a screenshot on test failure with JUnit?

A few quick searches led me to this:

http://blogs.steeplesoft.com/posts/2012/grabbing-screenshots-of-failed-selenium-tests.html

Basically, he recommends creating a JUnit4 Rule that wraps the test Statement in a try/catch block in which he calls:

imageFileOutputStream.write(
    ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES));

Does that work for your problem?


If you want to quickly add this behavior to ALL your tests in the run you can use the RunListener interface to listen for test failures.

public class ScreenshotListener extends RunListener {

    private TakesScreenshot screenshotTaker;

    @Override
    public void testFailure(Failure failure) throws Exception {
        File file = screenshotTaker.getScreenshotAs(OutputType.File);
        // do something with your file
    }

}

Add the listener to your test runner like this...

JUnitCore junit = new JUnitCore();
junit.addListener(new ScreenshotListener((TakesScreenShots) webDriver));

// then run your test...

Result result = junit.run(Request.classes(FullTestSuite.class));

If you want to take a screenshot on test failure, add this class

import java.io.File;

import java.io.IOException;

import java.util.UUID;

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;

import org.openqa.selenium.WebDriver;

public class ScreenShotOnFailure implements MethodRule {

    private WebDriver driver;

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

    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) {
                    captureScreenShot(frameworkMethod.getName());
                    throw t;
                }
            }

            public void captureScreenShot(String fileName) throws IOException {
                File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
                fileName += UUID.randomUUID().toString();
                File targetFile = new File("./Screenshots/" + fileName + ".png");
                FileUtils.copyFile(scrFile, targetFile);
            }
        };
    }
}

And Before all tests, you should use this Rule:

@Rule
public ScreenShotOnFailure failure = new ScreenShotOnFailure(driver));

@Before
public void before() {
   ...
}