selenium和appium中进行错误截图的操作

文章目录

  • 基本的截图方式
  • 进一步思考
  • 断言监听自动截图
    • 使用 IHookable 接口
    • 使用 TestListenerAdapter 接口
  • 其他

基本的截图方式

不管是 selenium 还是 appium 都可以使用的截图方式,都是通过 driver

File file = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(file, path);

getScreenshotAs 主要是驱动来调用做截图操作的,然后通过 FileUtils 的 copyFile 方法进行 file 的拷贝,拷贝到 path 路径下

进一步思考

对于这种截图方式,我们不用非要自己写在代码里头,我们可以封装成一个工具类,然后那里需要截图操作,我们使用工具类中的静态方法即可

再进一步思考,如果我们已经写好了一个截图的工具类了,然后我们还需要能够断言异常时候能自动监听该怎么办呢?请往下看

断言监听自动截图

有两种方式比较常用:

使用 IHookable 接口

本人使用的较少,此接口可以动态监听用例情况,可以重写 run 方法,run 方法调用自己写的截图工具类 ScreenshotUtil.takeScreenshot(driver)即可,具体使用如下:

public class TestResultListener implements IHookable {
	@Override
	public void run(IHookCallBack callBack, ITestResult testResult) {
		callBack.runTestMethod(testResult);
		if (testResult.getThrowable() != null) {
			// 这个地方要想办法把 driver 传进去,如果是多线程的话可以利用 ThreadLocal
			ScreenshotUtil.takeScreenshot(driver);
		}
	}
}

使用 TestListenerAdapter 接口

这种我用的比较多,因为这个接口可以通过调用各个阶段的方法,从而做各个阶段时期的工作,比如在 beforeSuite 阶段做一些 log 日志输出等

public class TestLogListener extends TestListenerAdapter {
	@Override
	public void onStart(ITestContext iTestContext) {
	    super.onStart(iTestContext);
	    log.info(String.format("====================%s开始====================", iTestContext.getName()));
	}
	
	@Override
	publicvoid onTestStart(ITestResult iTestResult) {
	    super.onTestStart(iTestResult);
	    log.info(String.format("========%s.%s测试开始========", iTestResult.getInstanceName(), iTestResult.getName()));
	}
	
	@Override
	public void onTestSuccess(ITestResult iTestResult) {
	    super.onTestSuccess(iTestResult);
	    log.info(String.format("========%s.%s测试通过========", iTestResult.getInstanceName(), iTestResult.getName()));
	}
	
	@Override
	public void onTestFailure(ITestResult iTestResult) {
	    super.onTestFailure(iTestResult);
	    log.error(String.format("========%s.%s测试失败,失败原因如下:\n%s========", iTestResult.getInstanceName(), iTestResult.getName(), iTestResult.getThrowable()));
	    // 失败时候抛出异常进行截图操作
	    ScreenshotUtil.takeScreenshot(iTestResult);
	}
	
	@Override
	public void onTestSkipped(ITestResult iTestResult) {
	    super.onTestSkipped(iTestResult);
	    log.info(String.format("========%s.%s跳过测试========", iTestResult.getInstanceName(), iTestResult.getName()));
	}
	
	@Override
	public void onFinish(ITestContext iTestContext) {
	    super.onFinish(iTestContext);
	    log.info(String.format("====================%s结束====================", iTestContext.getName()));
	}
}

值得注意的是我没有把保存在 ThreadLocal 中的驱动传进 takeScreenshot 而是把 iTestResult 传了进去,如果使用 ThreadLocal 保存 driver 避免多线程串扰是完全可以的,如果使用 iTestResult 其实也行,这是因为 iTestResult 可以强转成测试基类 BaseTest,如果 driver 在 BaseTest 中声明,那就可以拿到 driver,进而去做driver.getScreenshotAs的操作了,具体截图工具类的实现如下:

public class ScreenshotUtil {
    /**
     * 截图存储路径
     */
    private static String SCREENSHOT_PATH = System.getProperty("user.dir") + File.separator + "target" + File.separator + "test-output" + File.separator + "screenshot";

    /**
     * 截图
     *
     * @param iTestResult i测试结果
     */
    public static void capture(ITestResult iTestResult) {
        log.info("开始截图");
        // 拿到需要截图的驱动
        WebDriver driver = ((BaseTest) iTestResult.getInstance()).driver;
        // 截图目录
        File screenshotFile = new File(SCREENSHOT_PATH);
        // 若文件夹不存在就创建该文件夹
        if (!screenshotFile.exists() && !screenshotFile.isDirectory()) {
            screenshotFile.mkdirs();
        }
        // 截图格式
        String screenshotFormat = PropertiesReader.getKey("output.screenshot.format");
        // 哪个类导致的截图
        String className = iTestResult.getInstance().getClass().getSimpleName();
        // 时间格式
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年M月d日H时m分s秒");
        String timeStr = simpleDateFormat.format(new Date());
        // 截图名称
        String screenshotName = className + "-" + timeStr;
        try {
            // 截图操作
            File sourcefile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
            // 截图存储
            FileUtils.copyFile(sourcefile, new File(SCREENSHOT_PATH + File.separator + screenshotName + screenshotFormat));
        } catch (IOException e) {
            e.printStackTrace();
            log.error("截图操作异常!");
        }
    }
}

注意上面我有使用PropertiesReader.getKey("output.screenshot.format");这样的方法,这个类实际上是自己写的读取一个配置文件的内容,实际产生的还是一个 String,这里没做此类的具体展示,请酌情拷贝代码!

其他

另外常常会配合 allure 2 的报告使用,我们就要用上 @Attachment 注解配合上 String 或 byte[] 的返回值,可以方便 allure 2 报告中附上这些截图,具体使用方式请参考 allure 官网中怎么搭配 testng 使用

你可能感兴趣的:(Appium,TestNG)