java+testng+selenium实现测试用例过程的录制,生成GIF。(实现二)

1.实现原因

自动化测试执行发现在本地执行较快,在执行机上执行有时因并行其他任务导致执行较慢,所以导致录制不完全部过程,故此期望在点击、输入等方法中去截图,在用例成功和失败时去生成GIF,还是保留上次的通过注解控制的功能。

2.CaseBase部分的代码实现

所有的测试用例中相关的方法都是继承CaseBase的,在执行时CaseBase中的点击、输入等方法时去调用截图方法。

import org.apache.commons.io.FileUtils;
import org.openqa.selenium.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.Listeners;
import service.test.utility.TimelUtility;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.lang.*;
import static io.qameta.allure.Allure.step;

//初始化浏览器
@Listeners({ShotListener.class})
public class CaseBase {

	public DriverBase driverBase;
	public static final Logger logger = LoggerFactory.getLogger(CaseBase.class);
	private static final  String rootPath = System.getProperty("user.dir");

	private static final String PATH = System.getProperty("user.dir")+File.separator+"screenshot"+File.separator;

	@AfterClass(alwaysRun = true)
	public void closeBrowser(){
		logger.info("=================关闭浏览器=================");
		driverBase.closeBrowser();
	}

	public String isGenerateGif(){
		StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); // 获取调用父类方法A的堆栈元素(即子类方法B的信息)
		StackTraceElement caller = stackTrace[3];
		String callerClassName = caller.getClassName();// 获取类名
		// 获取当前测试类的简单名称(不包含包路径)
		String className = callerClassName.substring(callerClassName.lastIndexOf('.') + 1);
		String MethodName = caller.getMethodName(); // 获取方法名
		try { // 获取子类的Class对象
			Class<?> callerClass = Class.forName(callerClassName);
			// 获取所有声明的方法
			Method[] methods = callerClass.getDeclaredMethods();
			// 遍历并找到匹配的方法
			for (Method method : methods) {
				if (method.getName().equals(MethodName)) {
					// 找到匹配的方法 检查方法是否有注解
					if (method.isAnnotationPresent(GenerateGif.class)) {
						GenerateGif annotation = method.getAnnotation(GenerateGif.class);
						if(annotation == null || !annotation.value()){
							return "";
						}else {
							return PATH + className + File.separator + MethodName + File.separator;
						}
					} else {
						return "";
					}
				}
			}
			return "";

		} catch (Exception e) {
			e.printStackTrace(); // 捕捉异常并打印堆栈信息
			return "";
		}
	}





	private void screenshot(String gifPath){
		if(!gifPath.equals("")) {
			try {
				File screenshot = ((TakesScreenshot) driverBase.getDriver()).getScreenshotAs(OutputType.FILE); // 捕捉浏览器视口的截图
				File destination = new File(gifPath+ System.currentTimeMillis() + ".png"); // 截图保存的目标文件
				FileUtils.copyFile(screenshot, destination); // 复制截图到目标文件
			}catch (IOException e) {
				e.printStackTrace(); // 捕捉并打印异常
			}
		}
	}
	/**
	 * 用selenium自带方法点击元素
	 * @param stepMsg 步骤名称
	 * @param xpath 定位元素所需xpath表达式
	 */
	public void click(String stepMsg,String xpath){
		driverBase.click(stepMsg,locateElement(stepMsg,xpath));
		screenshot(isGenerateGif());
	}

3.ShotListener实现代码

用例成功或是失败时去生成GIF

import com.madgag.gif.fmsware.AnimatedGifEncoder;
import io.qameta.allure.Allure;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.*;
import org.testng.Assert;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.TestListenerAdapter;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;

//@Attachment 注解必须放在test文件夹下面
public class ShotListener3 extends TestListenerAdapter  {
	private static final String PATH = System.getProperty("user.dir")+File.separator+"screenshot"+File.separator;
	private static final int MAX_FARAME_INTERVAL_MS = 1000; // 每帧播放间隔 1000毫秒

	@Override
	public void onTestSuccess(ITestResult tr) {
		//判断测试方法是否有gif注解,生成gif
		if (isGenerateGif(tr)){
			getGenerateGif(getGifPath(tr));// 生成 GIF 动图
		}
	}

	@Override
	public void onTestSkipped(ITestResult tr) {
		//判断测试方法是否有gif注解,设置了失败重试时删除测试用例之前的截图
		if (isGenerateGif(tr)){
			rmdir(getGifPath(tr));
		}
	}

	@Override
	public void onTestFailure(ITestResult tr) {
		//请求失败截图
		screenshot(getDriver(tr));
		//判断测试方法是否有gif注解,生成gif
		if (isGenerateGif(tr)){
			String gifPath = getGifPath(tr);
			getGenerateGif(gifPath);// 生成 GIF 动图
		}


	}

	@Override
	public void onFinish(ITestContext context) {
		rmdir(PATH);
	}


	private boolean isGenerateGif(ITestResult tr){
		// 获取测试方法上的 @GenerateGif 注解
		GenerateGif GenerateGif = tr.getMethod().getConstructorOrMethod().getMethod().getAnnotation(GenerateGif.class);
		return  GenerateGif != null && GenerateGif.value(); // 根据注解决定是否捕捉截图
	}

	private WebDriver getDriver(ITestResult tr){
		//获取浏览器driver
		CaseBase bt = (CaseBase) tr.getInstance();
		return bt.driverBase.getDriver();

	}

	private String getGifPath(ITestResult tr) {

		// 获取当前测试类的完整路径
		String fullClassName  = tr.getTestClass().getName();
		// 获取当前测试类的简单名称(不包含包路径)
		String className = fullClassName.substring(fullClassName.lastIndexOf('.') + 1);
		// 获取当前执行的测试方法名
		String methodName  = tr.getMethod().getMethodName();

		String gifPath = PATH + className + File.separator + methodName + File.separator;

		return gifPath;
	}

	// 停止截图并生成 GIF 动图
	private void getGenerateGif(String gifPath) {

		try {
			InputStream content;
			takeGif(gifPath);//生成GIF
			File f= new File(gifPath + "screenshot.gif") ;
			content = new FileInputStream(f);
			Allure.addAttachment("用例执行过程如下:", content);
			content.close();
		}catch (IOException e) {
			e.printStackTrace(); // 捕捉并打印异常
		}
	}


	//	 将截图合成 GIF 动图
	private void takeGif(String gifPath){
		//合成gif图
		try {
			String[] pic = new File(gifPath).list();
			if (pic.length > 0){
				AnimatedGifEncoder e = new AnimatedGifEncoder();
				e.setRepeat(0);
				e.start(gifPath +"screenshot.gif");
				BufferedImage[] src = new BufferedImage[pic.length];
				for (int i = 0; i < src.length; i++) {
					e.setDelay(MAX_FARAME_INTERVAL_MS); //设置播放的延迟时间
					src[i] = ImageIO.read(new File(gifPath+pic[i])); // 读入需要播放的jpg文件
					e.addFrame(src[i]);  //添加到帧中
				}
				e.finish();
			}else {
				System.err.println(gifPath+"没有找到截图文件!");
			}
		} catch (IOException|Error e) {
			System.err.println(gifPath+"合成gif图失败!");
			e.printStackTrace();
		}
	}

	private void rmdir (String path) {
//		 创建File对象
		File file = new File(path);
//		 判断目录是否存在
		if (file.exists()) {
			// 删除目录
			try {
				FileUtils.forceDelete(file);
			} catch (IOException e) {
				System.err.println("删除文件目录 " + path + " 失败");
				e.printStackTrace();
			}
		}
	}
}

4.自定义注解

在测试方法上使用
在这里插入图片描述

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 创建GenerateGif自定义注解
 * 控制测试方法中是否需要录制GIF
 */
@Retention(RetentionPolicy.RUNTIME) // 注解在运行时可见
@Target(ElementType.METHOD) // 注解适用于方法
public  @interface GenerateGif {
    boolean value() default true; // 默认为 true,表示需要截图
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值