- 5 May 2012
- Java, Selenium
- 0 Comments
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://www.junit.org/node/580
Happy screenshot capturing!











