Capture screenshots when Selenium tests fail

This blog continues on my last blog on Selenium and demonstrates how to setup Junit4 to capture screenshots of the browser when  tests fail.

Create JUnit Rule

First, the rule in which JUnit uses to run and report test methods needs to be updated. This is done by implementing the interface org.junit.rules.MethodRule. JUnit provides a base class TestWatchman where we can extend:

public class ScreenShotRule extends TestWatchman {

...
 @Override
 public void failed(Throwable e, FrameworkMethod method) {
 // capture screenshot here
 }
}

Capture screenshots with Selenium

Selenium WebDriver implements the interface TakesScreenshot which indicates the web driver has the capability to capture screenshots. To enable this, the RemoteWebDriver instance needs to be augmented as below.

// In class AbstractRCTest (see my previous blog)
driver = new RemoteWebDriver(remoteUrl, capabilities);

 // Augment web driver for screenshot capture
 WebDriver augmentedDriver = new Augmenter().augment(driver);
 screenShotRule = new ScreenShotRule(augmentedDriver);

Now we can implement screenshot capture in class ScreenShotRule to take screenshots with Selenium and save it to file:

@Override
 public void failed(Throwable e, FrameworkMethod method) {
      File scrFile = ((TakesScreenshot) webdriver).getScreenshotAs(
                      OutputType.FILE);
      String scrFilename = method.getName() + "-Screenshot.png";
      File outputFile = new File("C:\\Temp", scrFilename);
      try {
           FileUtils.copyFile(scrFile, outputFile);
      } catch (IOException ioe) {
           log.error("Error copying screenshot after exception.", ioe);
      }
 }

Add rule to JUnit test class

Last thing to do is to set new rule in the unit test class

public class SampleRemoteTest {
     @Rule
     public ScreenShotRule screenShotRule;
     ...
}

That’s it. Now if a test fails, a screenshot will be taken of the browser in the server machine and saved into a local client where the test is run.

Advertisements

Automated Web site testing with Selenium

I will demonstrate in this blog how to set up Selenium to perform automated UI testing of web sites. Selenium provides different “parts” to support different testing purposes/scenarios. In this blog, I will focus on how to set up and run a remote Selenium Server and perform automated testing on a client machine. This setup is probably most appropriate from a development and deployment point of view.

Getting Selenium

First step is to download and set up Selenium Server to run on the server machine:

  1. Download the Selenium Server jar file from here and save it to a folder in your PC, e.g. C:\SeleniumServer
  2. To run tests for a browser other than Firefox using the Selenium server, you also need to download the respective browser driver. E.g. download the Internet Explorer Driver Server and follow the setup instruction for running tests on IE.
  3. To start the server, go to the folder in which jar file is saved and type:

C:\SeleniumServer>java -jar selenium-server-standalone-2.31.0.jar

Set up Project

With the Selenium Server up and running, we can start working on the project to write some UI tests using selenium. First we need to get the selenium jar files for the client. I use Maven and the pom file looks like

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>selenium-test</groupId>
 <artifactId>selenium-test</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <dependencies>
    <dependency>
       <groupId>org.seleniumhq.selenium</groupId>
       <artifactId>selenium-java</artifactId>
       <version>2.31.0</version>
    </dependency>
    <dependency>
       <groupId>com.opera</groupId>
       <artifactId>operadriver</artifactId>
    </dependency>
    <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
       <version>4.8.2</version>
    </dependency>
    <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-log4j12</artifactId>
       <version>1.6.4</version>
    </dependency>
 </dependencies>
<dependencyManagement>
 <dependencies>
    <dependency>
       <groupId>com.opera</groupId>
       <artifactId>operadriver</artifactId>
       <version>1.2</version>
       <exclusions>
          <exclusion>
             <groupId>org.seleniumhq.selenium</groupId>
             <artifactId>selenium-remote-driver</artifactId>
          </exclusion>
       </exclusions>
    </dependency>
 </dependencies>
</dependencyManagement>
</project>

Writing first Selenium test

First step here is to create an instance of RemoteWebDriver to connect to the Selenium Server:

@RunWith(Parameterized.class) // [1]
public abstract class AbstractRCTest {
/** Use this object to run all of your selenium tests */
 protected RemoteWebDriver driver; // [2]

 protected String browser;

 static Map<String, DesiredCapabilities> browserCapabilitiesMap; // [3]

 static { // [3]
      browserCapabilitiesMap = new LinkedHashMap<String, DesiredCapabilities>();
      browserCapabilitiesMap.put("*firefox", DesiredCapabilities.firefox());
      browserCapabilitiesMap.put("*iexplore", DesiredCapabilities.internetExplorer());
      browserCapabilitiesMap.put("*googlechrome", DesiredCapabilities.chrome());
 }

 @Parameters
 public static Collection<Object[]> generateData() {
      return Arrays.asList(new Object[][] {
          {"*firefox"},
          {"*googlechrome"}
         });
 }
public AbstractRCTest(String browser) throws MalformedURLException { 
      this.browser = browser;  
      DesiredCapabilities capabilities = browserCapabilitiesMap.get(browser);

      capabilities.setJavascriptEnabled(true);

      URL remoteUrl = new URL("http://localhost:4444/wd/hub"); // [4]
      driver = new RemoteWebDriver(remoteUrl, capabilities); // [5]
 }

Notes:

  1. JUnit4 parameterised test so as to run same tests for different browsers.
  2. This is the instance of RemoteWebDriver to be created to connect to Selenium Server.
  3. This setup the “desired capabilities” to be used as argument to constructor of RemoteWebDriver.
  4. Specify the URL of the Selenium Server. Note the “/wd/hub” at the end.
  5. Instantiate RemoteWebDriver with the URL and desired capabilities.

Now we are ready to write selenium tests. The following example attempts to connect to google.com and check the return page title:

public class SampleRemoteTest extends AbstractRCTest {

 public SampleRemoteTest(String browser) throws MalformedURLException {
      super(browser);
 }
 @Test
 public void testStub() throws Exception {
      driver.get("http://www.google.com");
      assertTrue(driver.getTitle().contains("Google"));
 }
}

The above test should run and pass. One potential gotcha is the Selenium Server requires the respective browser driver to be setup properly or you will get following error:

Exception: The path to the driver executable must be set by the webdriver.<browser>.driver system property...

This means the driver exe has not been put into the system PATH variable nor defined in Selenium Server JVM properties. I find that it is cleaner to do this in the command line when starting up the server, e.g. below is the Windows bat file to startup the Selenium Server for testing Chrome and IE:

java -jar selenium-server-standalone-2.31.0.jar 
-Dwebdriver.ie.driver=%cd%\iedriverserver.exe 
-Dwebdriver.chrome.driver=%cd%\chromedriver.exe

That’s it for now on Selenium.