ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

基于Java+Maven+Testng+Selenium+Log4j+Allure+Jenkins搭建一个WebUI自动化框架(5)失败用例截图与重试

2021-12-25 04:33:13  阅读:193  来源: 互联网

标签:截图 Java driver Selenium testng 重试 用例 import public


在UI自动化测试用例执行过程中,经常会有很多不确定的因素导致用例执行失败,比如网络原因、环境问题等,所以我们有必要引入重试机制(失败重跑),来提高测试用例执行稳定性。

准备工作:我们在进行失败截图保存到本地的时候,需要用到FileUtils类,该类是在commons-io包下的,所以我们需要先引入依赖:

<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>

一:失败用例截图:

1、创建一个用例失败截图监听类(TestResultListener,名字自起)实现IHookable接口,实现run方法。 IHookable接口的作用:动态替换每一个被@Test注解标注的方法,即每当运行到@Test注解的方法的时候,就会执行该类的逻辑。

代码如下:

@Override
public void run(IHookCallBack iHookCallBack, ITestResult iTestResult) {
    //保证@Test注解标注的测试方法能够正常执行
    iHookCallBack.runTestMethod(iTestResult);
    //判断用例结果是否异常
    if(iTestResult.getThrowable() != null){
        //testResult参数提供了getInstance方法,可以获取当前测试类的实例(对象)
        BaseTest baseTest = (BaseTest) iTestResult.getInstance();
        RemoteWebDriver driver = baseTest.driver;
        //保存到allure报表中
        saveScreenshotToAllure(takeScreenshotAsByte(driver));
        //保存到本地
        takeScreenshot(driver,"test_"+System.currentTimeMillis());
    }
}

2、在testng.xml文件中添加listener标签使监听器生效,代码如下:

<!--使监听器生效-->
<listeners>
    <listener class-name="com.lrc.listener.TestResultListener"></listener>
</listeners>

 3、在Listener类中添加@Attachment注解方法,将截图保存到allure报表中

@Attachment(value = "screenshot",type = "image/png")
public byte[] saveScreenshotToAllure(byte[] data){
    //返回的字节数组的数据 作为附件添加到Allure报表中--》@Attachment注解来实现的
    return data;
}

4、在Listener类中提供生成字节数组的截图数据

/**
 * 生成字节数组的截图数据
 * @param driver
 * @return
 */
public byte[] takeScreenshotAsByte(RemoteWebDriver driver){
    byte[] data = driver.getScreenshotAs(OutputType.BYTES);
    return data;
}

5、在Listener类中提供生成普通文件的截图数据,用于在本地也生成截图

/**
 * 生成截图以普通文件的形式,并且保存到本地
 * @param driver
 * @param fileName
 */
public void takeScreenshot(RemoteWebDriver driver, String fileName){
    File srcFile = driver.getScreenshotAs(OutputType.FILE);
    File destFile = new File(System.getProperty("user.dir")+"\\screenshot\\"+fileName+".png");
    try {
        FileUtils.copyFile(srcFile,destFile);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

 

整个失败用例截图类的代码:

package com.lrc.listener;

import com.lrc.common.BaseTest;
import io.qameta.allure.Attachment;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.IHookCallBack;
import org.testng.IHookable;
import org.testng.ITestResult;

import java.io.File;
import java.io.IOException;

/**
 * @param
 * @author lrc
 * @create 2021/12/19
 * @return
 * @description
 **/
public class TestResultListener implements IHookable {

    @Override
    public void run(IHookCallBack iHookCallBack, ITestResult iTestResult) {
        //保证@Test注解标注的测试方法能够正常执行
        iHookCallBack.runTestMethod(iTestResult);
        //判断用例结果是否异常
        if(iTestResult.getThrowable() != null){
            //testResult参数提供了getInstance方法,可以获取当前测试类的实例(对象)
            BaseTest baseTest = (BaseTest) iTestResult.getInstance();
            RemoteWebDriver driver = baseTest.driver;
            //保存到allure报表中
            saveScreenshotToAllure(takeScreenshotAsByte(driver));
            //保存到本地
            takeScreenshot(driver,"test_"+System.currentTimeMillis());
        }
    }

    @Attachment(value = "screenshot",type = "image/png")
    public byte[] saveScreenshotToAllure(byte[] data){
        //使用@Attachment注解来实现的返回的字节数组的数据 作为附件添加到Allure报表中
        return data;
    }

    /**
     * 生成字节数组的截图数据
     * @param driver
     * @return
     */
    public byte[] takeScreenshotAsByte(RemoteWebDriver driver){
        byte[] data = driver.getScreenshotAs(OutputType.BYTES);
        return data;
    }

    /**
     * 生成截图以普通文件的形式,并且保存到本地
     * @param driver
     * @param fileName
     */
    public void takeScreenshot(RemoteWebDriver driver, String fileName){
        File srcFile = driver.getScreenshotAs(OutputType.FILE);
        File destFile = new File(System.getProperty("user.dir")+"\\screenshot\\"+fileName+".png");
        try {
            FileUtils.copyFile(srcFile,destFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


}

整个testng.xml的代码:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="All Test Suite" parallel="tests" thread-count="2">
    <!--使监听器生效-->
    <listeners>
        <listener class-name="com.lrc.listener.TestResultListener"></listener>
    </listeners>
    <test name="测试">
        <classes>
            <class name="com.lrc.testcases.TestBaidu3"/>
        </classes>
    </test>
</suite>

下面,我们特意设置用例执行失败,查看用例失败截图是否会生成在allure报表中生成与在本地生成

执行结果:

(1)在本地文件有生成失败用例截图

 

在allure报表里也有生成失败用例截图:

 

二:失败用例重试

1、创建用例重试监听类(RetryListener,名字自起)实现testng包下的IRetryAnalyzer类,重写retry方法。

package com.lrc.listener;

import org.testng.IRetryAnalyzer;
import org.testng.ITestResult;

/**
 * @param
 * @author lrc
 * @create 2021/12/20
 * @return
 * @description
 **/
public class RetryListener implements IRetryAnalyzer {
    //最大重试次数
    private int maxRetryCount=3;
    //当前的重试次数
    private int currentRetryCount=0;

    @Override
    public boolean retry(ITestResult result) {
        //限制重试的最大次数,否则会进入死循环
        if(currentRetryCount < maxRetryCount) {
            //如果当前的重试次数没有达到限制,就去执行重试机制
            currentRetryCount++;
            return true;
        }else {
            return false;
        }
    }
}

2、添加一个全局注解属性修改的类,用于使@Test注解每次都能拥有retryAnalyzer属性,可以减去每个@Test注解都要配置retryAnalyzer属性操作

package com.lrc.listener;

import org.testng.IAnnotationTransformer;
import org.testng.IRetryAnalyzer;
import org.testng.annotations.ITestAnnotation;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * @param
 * @author lrc
 * @create 2021/12/20
 * @return
 * @description
 **/
public class GlobalAnnotationTransformer implements IAnnotationTransformer {
    //通过实现IAnnotationTransformer接口可以动态的修改@Test注解的属性
    public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
        // 获取@Test注解的RetryAnalyzer属性对象
        IRetryAnalyzer iRetryAnalyzer = annotation.getRetryAnalyzer();
        if (iRetryAnalyzer == null) {
            annotation.setRetryAnalyzer(RetryListener.class);
        }
    }
}

3、在testng.xml中添加listener标签,使得全局注解修改监听类生效

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="All Test Suite" parallel="tests" thread-count="2">
    <!--使监听器生效-->
    <listeners>
        <listener class-name="com.lrc.listener.TestResultListener"></listener>
        <listener class-name="com.lrc.listener.GlobalAnnotationTransformer"></listener>
    </listeners>
    <test name="测试">
        <classes>
            <class name="com.lrc.testcases.TestBaidu3"/>
        </classes>
    </test>
</suite>

下面,我们再来看看失败用例是否会重新运行,最大运行4次,由于上面我特意断言每个用例都失败,所以每个用例都应该运行4次:

每次用户执行失败,都会在本地生成失败截图,如下:

allure报表也会有失败截图,并且监听了当前用例失败重跑了几次:

在allure报表中看到Retries被重复执行了3次,点击每一次的执行结果,都会展示错误截图:

至此,失败用例截图与失败用例重试已经集成完成。

标签:截图,Java,driver,Selenium,testng,重试,用例,import,public
来源: https://www.cnblogs.com/lrc123/p/15709142.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有