本文共 5330 字,大约阅读时间需要 17 分钟。
在前面我的自动化测试框架系列文章中,有一个知识点没有讲到,现在补上。
在运行自动测试脚本时,经常会需要增加失败时自动截图的功能,以及失败重跑功能,下面介绍一下通过监听器的方式来实现自动截图和重跑功能。package com.dji.utils;import java.io.File;import java.text.SimpleDateFormat;import java.util.Date;import org.apache.commons.io.FileUtils;import org.openqa.selenium.OutputType;import io.appium.java_client.AppiumDriver;/** * 截图并保存至本地 * * @author Charlie.chen */public class ScreenShot { private AppiumDriver driver; // 测试失败截屏保存的路径 private String path; public LogUtil log=new LogUtil(this.getClass()); public ScreenShot(AppiumDriver driver){ this.driver=driver; path=System.getProperty("user.dir")+ "//snapshot//"+ this.getClass().getSimpleName()+"_"+getCurrentTime() + ".png"; } public void getScreenShot() { File screen = driver.getScreenshotAs(OutputType.FILE); File screenFile = new File(path); try { FileUtils.copyFile(screen, screenFile); log.info("截图保存的路径:" + path); } catch (Exception e) { log.error("截图失败"); e.printStackTrace(); } } /** * 获取当前时间 */ public String getCurrentTime(){ Date date=new Date(); SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH-mm-ss"); String currentTime=sdf.format(date); return currentTime; } public String getPath() { return path; } public void setPath(String path) { this.path = path; }}
在TestNG中TestListenerAdapter为监听器类,共有如下主要方法:
要想实现用例运行失败自动截图,只需新建一个类TestNGListener继承TestListenerAdapter,然后重写onTestFailure、onTestSkipped等方法,在这些方法中加入截图操作即可。
package com.dji.utils;import org.testng.ITestContext;import org.testng.ITestResult;import org.testng.TestListenerAdapter;import io.appium.java_client.AppiumDriver;/** * testNG执行case 失败后 ,testNG Listener会捕获执行失败 * 如果要实现失败自动截图,需要重写Listener的onTestFailure方法 * * @author Charlie.chen */public class TestNGListener extends TestListenerAdapter { private static AppiumDriver driver; LogUtil log = new LogUtil(this.getClass()); public static void setDriver(AppiumDriver driver) { TestNGListener.driver = driver; } @Override public void onTestSuccess(ITestResult tr) { log.info("Test Success"); super.onTestSuccess(tr); } @Override public void onTestFailure(ITestResult tr) { log.error("Test Failure"); super.onTestFailure(tr); ScreenShot screenShot = new ScreenShot(driver); screenShot.getScreenShot(); } @Override public void onTestSkipped(ITestResult tr) { log.error("Test Skipped"); super.onTestSkipped(tr); } @Override public void onStart(ITestContext testContext) { log.info("Test Start"); super.onStart(testContext); } @Override public void onFinish(ITestContext testContext) { log.info("Test Finish"); super.onFinish(testContext); }}
完成以上三步即可!!!
package com.dji.utils;import org.testng.IRetryAnalyzer;import org.testng.ITestResult;/** * 用例失败自动重跑逻辑 * @author Charlie.chen * */public class TestNGRetry implements IRetryAnalyzer { public LogUtil log = new LogUtil(this.getClass()); private int retryCount = 0; private int maxRetryCount=2; public boolean retry(ITestResult result) { if (retryCount <= maxRetryCount) { String message = "running retry for '" + result.getName() + "' on class " + this.getClass().getName() + " Retrying " + retryCount + " times"; log.info(message); retryCount++; return true; } return false; }}
package com.dji.utils;import java.lang.reflect.Constructor;import java.lang.reflect.Method;import org.testng.IAnnotationTransformer;import org.testng.IRetryAnalyzer;import org.testng.annotations.ITestAnnotation;/** * 添加用例重跑监听器,用例失败自动重跑功能 * * @author Charlie.chen * */public class RetryListener implements IAnnotationTransformer { public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) { IRetryAnalyzer retry = annotation.getRetryAnalyzer(); if (retry == null) { annotation.setRetryAnalyzer(TestNGRetry.class); } } }
以上三步就搞定用例失败重跑的功能了,但是最后我们查看testng报告时,发现失败的用例在报告里生成了多份,显然这样不好,那怎么解决呢?
我们来更改第一部分自动截图中说到的TestNGListener监听器类,重写onFinish方法
@Override public void onFinish(ITestContext testContext) { log.info("Test Finish"); IteratorlistOfFailedTests = testContext.getFailedTests().getAllResults().iterator(); while (listOfFailedTests.hasNext()) { ITestResult failedTest = listOfFailedTests.next(); ITestNGMethod method = failedTest.getMethod(); if (testContext.getFailedTests().getResults(method).size() > 1) { listOfFailedTests.remove(); } else { if (testContext.getPassedTests().getResults(method).size() > 0) { listOfFailedTests.remove(); } } } }