• TestNG监听器实现用例运行失败自动截图、重运行功能(转)


    使用Testng框架搭建自动测试框架,经常会需要增加失败自动截图,以及失败重跑功能,下面介绍一下不修改Testng的源码,通过监听器的方式来实现自动截图、重跑、以及自定义生成的Html结果文件功能。

    自动截图功能
    1、新建一个Java类继承TestListenerAdapter
    2、重写onTestFailure、onTestSkipped等方法,在这些方法中加入截图操作
    3、在testng.xml文件中配置自己编写的监听器类

    <listeners>

    <listener class-name="***.testng.TestngListener" /> </listeners>


    public class TestngListener extends TestListenerAdapter {

        private static Logger logger = Logger.getLogger(TestngListener.class);

        public static final String CONFIG = "config.properties";

       @Override

       public void onTestFailure(ITestResult tr) {

        super.onTestFailure(tr);  

      logger.info(tr.getName() + " Failure"); takeScreenShot(tr);

    }

    @Override

     public void onTestSkipped(ITestResult tr) {

      super.onTestSkipped(tr);

       logger.info(tr.getName() + " Skipped");

        takeScreenShot(tr);

     @Override

      public void onTestSuccess(ITestResult tr) {

      super.onTestSuccess(tr);

       logger.info(tr.getName() + " Success"); }

    }

    @Override

     public void onTestStart(ITestResult tr) {

      super.onTestStart(tr);

      logger.info(tr.getName() + " Start");

      }

    @Override

    public void onFinish(ITestContext testContext) {

    super.onFinish(testContext);

    /** * 自动截图,保存图片到本地以及html结果文件中 *

    * @param tr

    */

    private void takeScreenShot(ITestResult tr) {

    SimpleDateFormat formatter = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");

    String mDateTime = formatter.format(new Date());

    String fileName = mDateTime + "_" + tr.getName();

    String filePath = OrangeiOS.driver.getScreenshotAs(fileName);

    Reporter.setCurrentTestResult(tr);

    Reporter.log(filePath);

    //这里实现把图片链接直接输出到结果文件中,通过邮件发送结果则可以直接显示图片 Reporter.log("<img src="../" + filePath + ""/>"); }


    失败自动重跑功能
    1、新建Java类实现IRetryAnalyzer接口

    public class TestngRetry implements IRetryAnalyzer {

    private static Logger logger = Logger.getLogger(TestngRetry.class);

    private int retryCount = 1;

    private static int maxRetryCount;

    private static ConfigReader config;

    static {

    //外围文件配置最大运行次数 config = new ConfigReader(TestngListener.CONFIG);

    maxRetryCount = config.getMaxRunCount();

    logger.info("maxRunCount=" + (maxRetryCount));

    }

    @Override

    public boolean retry(ITestResult result) {

    if (retryCount <= maxRetryCount) {

    String message = "running retry for '" + result.getName() + "' on class " +

    this.getClass().getName() + " Retrying " + retryCount + " times"; logger.info(message);

    Reporter.setCurrentTestResult(result);

    Reporter.log("RunCount=" + (retryCount + 1));

    retryCount++; return true; } return false; } }

    2、新建Java类实现IAnnotationTransformer接口

    public class RetryListener implements IAnnotationTransformer{

    @Override

    public void transform(ITestAnnotation annotation, Class testClass,

    Constructor testConstructor, Method testMethod) {

    IRetryAnalyzer retry = annotation.getRetryAnalyzer();

    if (retry == null) { annotation.setRetryAnalyzer(TestngRetry.class); } } }


    3、在build.xml或者testng.xml文件中添加RetryListener监听器

    上面三步就可以实现失败自动重跑了,是不是比较方便,不过添加了重跑功能后会发现测试结果的邮件中用例的个数增加了,比如我只有一个用例,失败重跑了2次,一共运行3次,测试结果中显示的用例个数会是3个,那接下来就需要解决这个问题了。

    首先解决TestNg生成的index.html文件中个数不对的问题,这个问题只需要在Testng监听器的onFinish方法中,等所有用例运行完之后,检查用例,按照class+method+dataprodiver的名称生成hashcode获取唯一id,如果fail的用例中存在重复的则在 fail的用例中剔除掉,具体代码如下:

    @Override

    public void onFinish(ITestContext testContext) {

    super.onFinish(testContext);

    // List of test results which we will delete later

    ArrayList<ITestResult> testsToBeRemoved = new ArrayList<ITestResult>();

    // collect all id's from passed test

    Set<Integer> passedTestIds = new HashSet<Integer>();

    for (ITestResult passedTest : testContext.getPassedTests().getAllResults()) {

    logger.info("PassedTests = " + passedTest.getName()); passedTestIds.add(getId(passedTest)); }

    Set<Integer> failedTestIds = new HashSet<Integer>();

    for (ITestResult failedTest : testContext.getFailedTests().getAllResults()) {

    logger.info("failedTest = " + failedTest.getName());

    // id = class + method + dataprovider

    int failedTestId = getId(failedTest);

    // if we saw this test as a failed test before we mark as to be deleted

    // or delete this failed test if there is at least one passed version

    if (failedTestIds.contains(failedTestId) || passedTestIds.contains(failedTestId)) {

    testsToBeRemoved.add(failedTest);

    }

    else

    { failedTestIds.add(failedTestId); }

    }

    // finally delete all tests that are marked

    for (Iterator<ITestResult> iterator =

    testContext.getFailedTests().getAllResults().iterator(); iterator.hasNext();)

    { ITestResult testResult = iterator.next();

    if (testsToBeRemoved.contains(testResult))

    { logger.info("Remove repeat Fail Test: " + testResult.getName()); iterator.remove(); }

    } }

    private int getId(ITestResult result) {

    int id = result.getTestClass().getName().hashCode();

    id = id + result.getMethod().getMethodName().hashCode();

    id = id + (result.getParameters() != null ? Arrays.hashCode(result.getParameters()) : 0);

    return id;

    }



    当前失败重跑也存在一些小问题:
    1、setup中出现的错误直接是skip的,不会重跑
    2、如果存在dataprodiver,则第二组数据以后的用例是不会重跑的
    3、testng自带生成的emailable-report.html文件中用例的个数也不对了,这个问题可以自行修改EmailableReporter.java文件


    如何修改自定义emailable-report.html

    emailable-report.html是Testng运行完成后自动生成的,经常运行结束后我们会把这个文件作为邮件正文发送给收件人,如果我们要修改这个文件内容怎么办呢?

    1、首先emailable-report.html文件的生成TestNG是实现了IReporter接口,那我们可以直接从源代码中取出这个文件源代码
    https://github.com/cbeust/testng/blob/master/src/main/java/org/testng/reporters/EmailableReporter.java
    2、针对源代码进行自己修改
    3、把修改后的源代码加入自己的工程
    4、在build.xml文件中新增自定义的监听器,运行时就会调用自定义的监听器生成想要的html文件了

    <testng outputDir="test-output" classpathref="http://qa.blog.163.com/blog/runpath" haltonfailure="false" listeners="com.****.CustomerEmailableReport" > <xmlfileset dir="." includes="${testngxml}.xml" /> </testng>

     

     

     

  • 相关阅读:
    mac 卸载 node并重新安装
    最小的Django应用
    Python如何实现文本转语音
    Python语言库pyttsx3
    大数据资料
    剑指offer(29)最小的K个数
    剑指offer(28)数组中出现次数超过一半的数
    剑指offer(27)字符串的排列
    剑指offer(26)二叉搜索树与双向链表
    JS、JAVA刷题和C刷题的一个很重要的区别
  • 原文地址:https://www.cnblogs.com/jack1989/p/7728792.html
Copyright © 2020-2023  润新知