import java.net.URL;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.DriverCommand;
import org.openqa.selenium.remote.RemoteWebDriver;
public class CustomRemoteWebDriver extends RemoteWebDriver implements
TakesScreenshot {
public CustomRemoteWebDriver(URL url, DesiredCapabilities dc) {
super(url, dc);
}
@Override
public X getScreenshotAs(OutputType target)
throws WebDriverException {
if ((Boolean) getCapabilities().getCapability(
CapabilityType.TAKES_SCREENSHOT)) {
return target
.convertFromBase64Png(execute(DriverCommand.SCREENSHOT)
.getValue().toString());
}
return null;
}
}
然后,我们在加一个封装类, 将截图方法放进去。
WebDriverWrapper.screenShot :
/**
* Function to take the screen shot and save it to the classpath dir.
* Usually, you will find the png file under the project root.
*
* @param driver
* Webdriver instance
* @param desc
* The description of the png
*/
public static void screenShot(WebDriver driver, String desc) {
Date currentTime = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss");
String dateString = formatter.format(currentTime);
File scrFile = ((TakesScreenshot) driver)
.getScreenshotAs(OutputType.FILE);
try {
desc = desc.trim().equals("") ? "" : "-" + desc.trim();
File screenshot = new File("screenshot" + File.separator
+ dateString + desc + ".png");
FileUtils.copyFile(scrFile, screenshot);
} catch (IOException e) {
e.printStackTrace();
}
}
下面,就是添加 Junit 的 TestRule:
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.openqa.selenium.WebDriver;
public class TakeScreenshotOnFailureRule implements TestRule {
private final WebDriver driver;
public TakeScreenshotOnFailureRule(WebDriver driver) {
this.driver = driver;
}
@Override
public Statement apply(final Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
try {
base.evaluate();
}
catch (Throwable throwable) {
WebDriverWrapper.screenShot(driver, "assert-fail");
throw throwable;
}
}
};
}
}
代码很简单,在抛出 evalate 方法的错误之前,截图。
然后就是使用这个 TestRule, 很简单,只要在你的 测试用例里面加入:
public class MyTest {
...
@Rule
public TestRule myScreenshot = new TakeScreenshotOnFailureRule(driver);
...
@Test
public void test1() {}
@Test
public void test2() {}
...
}
即可。关于 Junit 的 Rule 请自行 google!
两则的比较
总得来说,两种方法都很方便, 也很有效果, 基本都能截图成功。
不同之处在于,
RemoteWebDriver 监听器是在 RemoteWebDriver 抛出异常的时候截图。
TestRule 是在 assert 失败的时候截图。
我在项目中最早是用第一种方法,后来改用第二种,主要是因为,在自定义的监听器里, 它遇到所有的异常都会截图,这个时候,如果你用了 condition wait 一个 Ajax 的元素, 那就会很悲剧,你会发现在你的目录下面有无数的截图。当初我没有找到解决方法,期待有人提出。