WebDriver测试失败后自动获取截图

UI自动化测试其实并不是那么稳定,可能是因为UI元素的改动,也可能是因为网络的不稳定,在测试失败的时候,WebDriver通常会抛出一些异常;通过异常信息通常都能知道大概是哪里出错了,但是如果能加上截屏,那就更加好了。尤其是用Remote WebDriver运行测试,所有测试都是通过Selenium Grid分发到各个节点来运行,不同节点的配置还有可能不是完全一样。

如果是使用RemoteWebDriver的话,它提供了一个很好的功能,就是会把运行测试发生异常时候的截图也放到异常里面,具体可以参考RemoteWebDriver的简介。代码很简单:

public String extractScreenShot(WebDriverException e) {
    Throwable cause = e.getCause();
    if (cause instanceof ScreenshotException) {
        return ((ScreenshotException) cause).getBase64EncodedScreenshot();
    }
    return null;
}

怎么样才能在异常发生的时候自动把异常抓住呢?简单来说就是要对写测试代码的人是透明了,在写测试代码的时候不需要特别去处理异常。这里需要实现WebDriverEventListener接口,然后把RemoteWebDriver对象和实现WebDriverEventListener接口的对象包到一起,实例化一个EventFiringWebDriver对象。之后的事情就跟用一个普通的RemoteWebDriver对象没有任何区别。

实现WebDriverEventListener接口的一个例子:

public class MyEventListener implements WebDriverEventListener {
    public void onException(Throwable ex, WebDriver arg1) {
        String filename = generateRandomFilename(ex);
        try {
            byte[] btDataFile = Base64.decodeBase64(extractScreenShot(ex).getBytes());
            File of = new File(filename);
            FileOutputStream osf = new FileOutputStream(of);
            osf.write(btDataFile);
            osf.flush();
            osf.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private String generateRandomFilename(Throwable ex) {
        Calendar c = Calendar.getInstance();
        String filename = ex.getMessage();
        int i = filename.indexOf('\n');
        filename = filename.substring(0, i).replaceAll("\\s", "_")
                    .replaceAll(":", "")
                    + ".png";
                    filename = "" + c.get(Calendar.YEAR) + "-" + c.get(Calendar.MONTH)
                    + "-" + c.get(Calendar.DAY_OF_MONTH) + "-"
                    + c.get(Calendar.HOUR_OF_DAY) + "-" + c.get(Calendar.MINUTE)
                    + "-" + c.get(Calendar.SECOND) + "-" + filename;
        return filename;
    }

    private String extractScreenShot(Throwable ex) {
        Throwable cause = ex.getCause();
        if (cause instanceof ScreenshotException) {
            return ((ScreenshotException) cause).getBase64EncodedScreenshot();
        }
        return null;
    }

    @Override
    public void afterChangeValueOf(WebElement arg0, WebDriver arg1) {
    // TODO Auto-generated method stub

    }
}

实例化一个EventFiringWebDriver对象:

@Test
public void setup(){
    String remote_driver_url = "http://localhost:4444/wd/hub";
    DesiredCapabilities capability = null;
    capability = DesiredCapabilities.firefox();
    WebDriverEventListener eventListener = new MyEventListener();
    WebDriver driver = new EventFiringWebDriver(new RemoteWebDriver(new URL(
                    remote_driver_url), capability)).register(eventListener);
}

之后如果测试遇到任何异常,都会在basedir(这个是要自己配置的)下面生成一个类似这样的png截图(2011-7-22-20-55-9-Element_is_not_currently_visible_and_so_may_not_be_interacted_with.png)。

这些代码段演示了如何使用WebDriverEventListener接口以及EventFiringWebDriver类,实现监听测试中所抛出的异常,并且把异常里面附带的截图保存为png文件。

参考博客:Generating a screen capture on exception thrown with Selenium 2

5 thoughts on “WebDriver测试失败后自动获取截图”

  1. hi:
    你的文章确实很有用,非常感谢
    但我发现我用的时候当我上面方法实例化一个EventFiringWebDriver对象时,运行会报错,错误就是invalid address or can not locate browser为什么,非学疑惑,这几天一直在查找原因。求赐教非常感谢

    1. 多谢你的留言。我已经有很长时间没有看相关的东西了,所以不一定能帮到你。

      我那时候用的是Selenium hub模式,就是在一台机器上起一个主的hub,然后其他selenium的机器连接那个hub,所以我的地址是:http://localhost:4444/wd/hub

      如果你用的是一般的selenium,而非hub,那么可以尝试一下把“http://localhost:4444/wd/hub”替换成你本地相对应的selenium url

      1. 非常感谢你的回复,有个问题就是我用junit+selenium进行测试时,因为web remotedriver在WIKI上看它有一个重要的功能 就是它的exception会有截图,我也看到你的这段代码用remotedirver来初始webdriver的原因,public void setup(){
        String remote_driver_url = “http://localhost:4444/wd/hub”;
        DesiredCapabilities capability = null;
        capability = DesiredCapabilities.firefox();
        WebDriverEventListener eventListener = new MyEventListener();
        WebDriver driver = new EventFiringWebDriver(new RemoteWebDriver(new URL(
        remote_driver_url), capability)).register(eventListener);
        }这段我如果要用selenium hub模式的时候,需要什么特殊配置之类的吗,比如说要下载selenium-server-standalone-2.35.0.jar之类的,或者有什么特殊的配置才能这么用。因为我感觉应该是有一些特殊配置或者前置条件才能用remote webdriver,谢谢,请问您当时是有什么特殊的配置之类的吗

Leave a Reply

Your email address will not be published. Required fields are marked *