基於Java+Maven+Testng+Selenium+Log4j+Allure+Jenkins搭建一個WebUI自動化框架(5)失敗用例截圖與重試


在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次,點擊每一次的執行結果,都會展示錯誤截圖:

至此,失敗用例截圖與失敗用例重試已經集成完成。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM