ui自动化设计思路

小伙伴让我周末做技术分享,想着这是一件有意义的事情,便答应了下来,那就给大家讲讲ui自动化吧。这里会结合具体的代码给大家讲ui自动化一些理念,方案设计。

本文将探讨ui自动化设计思路,主要围绕以下方面展开讲解,希望阅读前对ui自动化有个基本了解

1、单例模式的运用

2、ui自动化分层思想

    2.1PageObject设计模式

    2.2业务流程封装

3、测试数据的准备

    3.1 调用APi创建测试数据

    3.2数据库操作创建测试数据

    3.3数据驱动

    3.4测试数据自动生成技术

4、ui自动化测试报告

     4.1 调用 screenshot 函数实现截图

     4.2 保存服务器日志

    4.3 结合testng监听器对失败用例实时截图

5、ui自动化稳定性的关键技术

     5.1   重试机制

     5.2   异常场景恢复模式 

     5.3   元素模糊匹配

6、ui自动化执行效率的提升

7、无头浏览器的运用

8、分布式Selenium Grid运用

9、黑科技

     9.1  页面对象自动生成技术

     9.2  测试数据自动生成技术

1、单例模式的运用

在编写ui代码的时候,我们在很多地方都需要WebDriver对象,难道每次都new一个实例?这样会创建很多浏览器进程,我们只需要运用单例设计模式就可以解决这个问题,只有一个相同的WebDriver对象,需要时直接WebDriver driver = SingletonWebDriver.getWebDriver("chrome");

package com.yck.gui.utils;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.TimeUnit;

import org.openqa.selenium.Platform;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;

public class SingletonWebDriver {

	private static final String URL = "http://127.0.0.1:14444/wd/hub";
	private static final int DRIVER_WAIT_TIME = 20;
	private static WebDriver instance = null;

	private SingletonWebDriver() {
	}

	public static WebDriver getWebDriver(String browserName) {

		switch (browserName) {
		case "chrome":
			try {
				instance = new RemoteWebDriver(new URL(URL), getCapabilitity(browserName));
			} catch (MalformedURLException e1) {
				e1.printStackTrace();
			}
			break;

		case "firefox":
			try {
				instance = new RemoteWebDriver(new URL(URL), getCapabilitity(browserName));
			} catch (MalformedURLException e1) {
				e1.printStackTrace();
			}
			break;
		}
		instance.manage().timeouts().implicitlyWait(DRIVER_WAIT_TIME, TimeUnit.SECONDS); // second为等待时间,单位秒
		return instance;

	}

	public static DesiredCapabilities getCapabilitity(String browserName) {
		DesiredCapabilities capability = DesiredCapabilities.chrome();
		capability.setBrowserName(browserName);
		capability.setPlatform(Platform.LINUX);
		return capability;
	}

}

2、ui自动化分层思想

2.1   PageObject设计模式

在实际编写脚本中,假如把控件操作和测试用例写在一起,是不是会觉得代码难以维护,可读性极差。假如某一个控件被很多用例使用,这个控件发生变化,我们需要修改所有引用这个控件的用例,这样效率及其低下。我们可以引入页面对象模型解决这种问题。

页面对象模型的核心思想就是以页面为单位来封装页面的控件和部分操作,在测试用例的编写中,需要对某个页面进行操作的时候,直接XXXPage.XXX.Compent.XXXOperation();

页面对象模型有如下优点

1、用例与操作解耦,解决了代码可读性差,难以维护的问题。

2、代码重用性高,当某个控件或操作步骤被多个用例引用时,我们只需要这个相同的控件。

2.2  基于业务流程封装

业务流程抽象是基于操作函数的更接近于实际业务的更高层次的抽象方式,有点拗口,举个例子就明白了。

一个注册业务包含用户注册、实名认证、后台审核这三步,我们就可以把这三步作为独立的类进行封装,也很方便的被其它业务流程重用。类的内部通常是调用操作函数,操作函数内部是基于页面对象模型完成具体的页面操作。业务流程封装更接近实际业务,遵循参数准备,实例化对象,给对象赋值,执行操作这四步。

3、测试数据的准备

3.1 调用APi创建测试数据

测试数据直接由相关api生成,这种不会存在脏数据的问题,测试数据也比较稳定,缺点就是不是所有的测试数据都可以通过api生成,对于需要创建大量测试数据的场景来说,这种方式的效率也不是很理想。

3.2数据库操作创建测试数据

实际项目中,不是所有的数据都有相关api支持,因为有的数据直接在代码中生成和修改且不对外提供接口,那么这种情况下,就需要操作数据库来生成测试数据。我们可以把操作数据库的封装成一个工具类,直接传入sql语句即可。但是这个也有个明显的缺点,就是接口改了,或者数据库表结构改了,要是sql语句更新不及时,就会导致用例的数据问题。

所以ui自动化最好的方式还是通过页面操作,其次api调用生成测试数据,最后通过数据库CRUD。

3.3数据驱动

数据驱动实现了测试脚本与数据解耦,就是把数据源存在csv、xls、yaml、数据库中,需要的时候去相应文件中获取。

testng的Data Provider很好的实现数据驱动,我的另一篇博客有详细案例。

3.4测试数据自动生成技术

      详见9.2

4、ui自动化测试报告

测试报告是ui自动化中很重要的一部分,当测试用例执行失败时,我们不需要手工复现失败场景,只需要去分析测试报告,查找失败的原因。对于测试报告需要包含浏览器界面截图跟服务器日志两部分。浏览器截图是为了知道用例是在什么界面什么操作出错了,服务器日志是为了方便定位代码问题。

4.1  调用 screenshot 函数实现截图,封装了工具类如下

注意,截图图片命名要规范,可以用url或者用例名称命名

package com.yck.gui.utils;

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

import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

public class ScreenShotsUtil {

	private static final String FILE_PATH = "./Screenshots/";

	public void ScreenShotByElement(WebElement webElement) {
		File src = webElement.getScreenshotAs(OutputType.FILE);
		try {
			FileUtils.copyFile(src, new File(FILE_PATH + webElement.toString() + ".png"));
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	public void ScreenShotByDriver(WebDriver driver) {
		File src = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
		try {
			FileUtils.copyFile(src, new File(FILE_PATH + driver.getCurrentUrl() + ".png"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

4.2  保存失败用例服务器日志

package com.yck.gui.utils;

import ch.ethz.ssh2.Connection;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;

public class RemoteServiceLogUtil {

	public static void main(String[] args) {
		RemoteServiceLogUtil r = new RemoteServiceLogUtil();
		String a = r.execute("10.100.35.146", 22, "root", "helpDesk.com", "tail -99f /opt/local/mall/api.out");
		System.out.println("aa"+a);

	}

	public String processStdout(InputStream in) {
		InputStream input = new StreamGobbler(in);
		StringBuffer buffer = new StringBuffer();
		BufferedReader br;
		
		try {
			br = new BufferedReader(new InputStreamReader(input, "UTF-8"));
			String line = null;
			while ((line=br.readLine()) .length()>0) {
				buffer.append(line + "\n");
				
			}
			input.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return buffer.toString();
	}

	public String execute(String host, int port, String userName, String passWord, String cmd) {
		Connection conn = new Connection(host);
		String result = null;
		Session session = null;
		

		try {
			conn.connect();
			boolean isconn = conn.authenticateWithPassword(userName, passWord);
			
			if (!isconn) {
				System.out.println("服务器连接失败");
			}
			session = conn.openSession();
			session.execCommand(cmd);// 执行命令
			result = processStdout(session.getStdout());
			conn.close();
			session.close();

		} catch (IOException e) {
			e.printStackTrace();
		}

		return result;

	}

}

4.3 结合testng监听器对失败用例实时截图

5、ui自动化稳定性关键技术

做过ui自动化的同学,我相信你们都遇到过测试稳定性的问题,在相同的环境,时而执行成功,时而执行失败,这会浪费很多时间去排查问题,ui自动化产出比也不高,所以ui自动化的稳定性关乎整个产出收益。

5.1   重试机制

页面响应延迟导致元素定位失败,环境不稳定,这些异常情况都会导致用例执行失败,所以加入重试机制会很好的解决这方面的问题。重试可以是用例级别的,也可以是步骤或者业务流程级别的。

下面结合testng对失败用例重试

5.2   异常场景恢复模式

在测试用例执行过程中,操作系统和被测系统可能会突然弹出对话框,因为你不知道在哪一步骤会弹出什么对话框,你就无法预先处理弹框,这样会导致元素定位失败,造成ui自动化不稳定。在手工测试过程中,你遇到弹框是不是直接关掉?对于ui自动化来说,处理方式也是一样,当出现元素无法定位时,就进入异常场景恢复模式,程序依次检查各种可能出现的对话框,一旦确认了对话框的类型,就直接关掉,接着重试刚刚失败的用例。

5.3   元素模糊匹配

页面元素发生细微的变化,也会导致元素定位失败,我们可以加入模糊匹配技术,提高控件的识别率。

6 、ui自动化执行效率的提升

6.1   基于testng多线程执行

6.2   Selenium Grid 分布式执行

6.3   减少等待时间

6.4   无头浏览器的运用

7、无头浏览器的运用

无头浏览器,即Headless Browers,是一种没有界面的浏览器,主要用于ui自动化,网络爬虫,页面监控等方面。

业界比较成熟的当属Google 的Chrome Headless和Phantomjs,不过Phantomjs已经停止维护,建议使用Chrome Headless。

Headless Browers在ui自动化中有如下优点

1、测试执行速度更快,少了css加载和页面渲染

2、cpu/内存的开销较低

3、在单机上运行多个无头浏览器,实现测试用例的并发执行

无头浏览器的缺点是,不能完全模拟真实的用户行为,而且由于没有实际完成页面的渲染,所以不太适用于需要对于页面布局进行验证的场景。

8、分布式Selenium Grid运用

selenium主要解决了测试重复执行和浏览器兼容性的问题。当用例达到一定数量的时候,单个浏览器执行全部用例需要数个小时,那多个浏览器呢?自动化测试的执行一般在产品发布之前几个小时,这样会严重影响产品的发布时间。当然最笨的办法是在多台主机部署多套浏览器环境,把测试用例分开执行即可,你会不会又觉得这样很麻烦。Selenium Grid就解决了分布式执行测试的痛点。

Selenium Grid跟Jmeter分布式压测一样,所谓的分布式就是由一个hub节点和若干个node代理节点组成。Hub用来管理各个代理节点的注册信息和状态信息,并且接受远程客户端代码的请求调用,然后把请求的命令转发给代理节点来执行。下面结合环境部署来理解Hub与node节点的关系,强烈建议使用docker构建环境。

下载hub镜像

docker pull selenium/hub

下载chrome镜像

docker pull selenium/node-chrome

启动hub镜像

docker run -d -p 4444:4444 --name selenium-hub selenium/hub

-d  容器后台运行,并返回容器id

-p  4444:4444    端口映射,容器4444端口映射到宿主机端口4444,即通过本机端口访问容器

--name selenium-hub  指定容器名称为selenium-hub

访问http://127.0.0.1:4444/grid/console,出现如下图表明启动成功 

启动Chrome镜像,连接hub,注册到Selenium Grid集群中

docker run -d --link selenium-hub:hub --name selenium-chrome selenium/node-chrome

启动chrome-headles浏览器,注册到Selenium Grid集群中去。

docker run -d  --link selenium-hub:hub alpeware/chrome-headless-trunk

启动firefox浏览器,注册到Selenium Grid集群中去。

docker run -d  --link selenium-hub:hub selenium/node-firefox

如下图表明浏览器node已经注册到hub中

通过Selenium Grid访问,代码如下

  • private static final String URL = "http://127.0.0.1:4444/wd/hub";
    
    DesiredCapabilities capability = DesiredCapabilities.chrome();
    
    capability.setBrowserName("chrome");
    
    capability.setPlatform(Platform.LINUX);
    
    WebDriver driver = new RemoteWebDriver(new URL(URL), capability);

<think>嗯,用户问的是UI自动化元素自愈的设计思路,我需要先理解这个概念。UI自动化测试中,元素定位失败是常见的问题,可能是因为元素属性变化、页面加载延迟或者动态ID等原因。自愈设计就是让测试脚本在遇到元素定位失败时能够自动修复,而不用人工干预。 首先,我得回忆一下常见的元素定位失败的原因。比如,元素的ID可能每次都会变,或者XPath路径因为页面结构变化而失效。这时候,传统的做法是测试失败,需要人工去更新定位器。但自愈设计的目标是自动处理这些问题,提高测试的稳定性和维护效率。 接下来,设计思路可能包括几个方面。首先是多属性备用定位策略,也就是为每个元素准备多个定位方式,比如同时用ID、CSS选择器、XPath等。当一种方式失败时,尝试其他方式。比如,如果一个按钮的ID变了,可以尝试用class或者文本内容来定位。 然后是动态属性处理,比如有的元素属性是动态生成的,每次都不一样。这时候可能需要用部分匹配,比如使用XPath的contains函数或者CSS的属性选择器,匹配部分属性值。例如,ID可能是“button-12345”,可以用正则表达式匹配“button-”开头的那部分。 还有智能等待机制,页面加载慢可能导致元素找不到,所以需要设置合理的等待时间,比如显式等待,直到元素出现或者可点击。另外,结合重试机制,在定位失败时自动重试几次,避免因为短暂的延迟导致失败。 元素快照对比也是一个点,当元素定位失败时,可以截图保存当前页面,和之前的版本对比,找出元素的变化,自动调整定位策略。比如,如果按钮的位置变了,通过图像识别技术重新定位。 上下文感知修复,可能需要分析页面结构的变化,比如父元素变了,导致子元素的路径失效。这时候可能需要根据相对位置或者兄弟元素来重新定位。例如,如果某个输入框的父div的class变了,可以寻找相邻的标签元素来定位。 最后是自愈后的验证,修复定位后,需要验证元素是否真的正确,比如点击后是否跳转到正确的页面,或者输入是否正确。同时,要记录自愈的过程和结果,方便后续分析和优化。 用户可能需要具体的例子或者实现步骤,所以应该给出一个实际的例子,比如登录按钮的定位策略。另外,需要注意用户可能对某些技术细节不太熟悉,比如动态XPath或者图像识别,可能需要简要解释。还要考虑用户的实际应用场景,比如是否在移动端或Web端,不同的平台可能有不同的解决方案。 总结下来,设计思路主要包括多定位策略、动态属性处理、智能等待和重试、元素快照对比、上下文感知修复以及自愈验证和记录。这些方法结合起来,可以提高UI自动化测试的稳定性和可靠性,减少维护成本。</think>UI自动化元素自愈(Self-healing)是提升测试脚本健壮性的关键技术,其核心目标是在元素定位失效时自动修复定位策略。以下是具体设计思路及实现步骤: --- ### **1. 多维度元素特征提取** 为每个控件建立**多属性特征库**: - 基础属性:ID、class、name、text、XPath等 - 层级关系:父节点/子节点的标签层级 - 视觉特征:坐标位置、颜色、尺寸(需结合OCR/图像识别) - 行为特征:可点击性、输入类型等 示例代码结构: ```python element_profile = { "login_button": { "attributes": { "id": "btn_login", "text": "登录", "xpath": "//div[@class='container']/button[1]" }, "visual": { "position": (120, 300), "color": "#007bff" } } } ``` --- ### **2. 动态权重评估机制** 建立属性权重评分体系: | 属性类型 | 初始权重 | 动态调整规则 | |----------------|----------|----------------------------------| | ID | 90 | 若含动态哈希值则降权至30 | | AccessibilityID | 85 | 平台专用属性保持高权重 | | XPath | 60 | 绝对路径检测到变化时降权至20 | | 图像特征 | 75 | 布局变化时自动启用 | --- ### **3. 三级自愈触发流程** ```mermaid graph TD A[元素定位失败] --> B{首次定位尝试} B -->|成功| C[正常执行] B -->|失败| D[启动备用定位策略] D --> E{使用第二属性定位} E -->|成功| F[更新定位器缓存] E -->|失败| G[启动智能修复] G --> H[DOM树分析+视觉识别] H --> I[生成新定位策略] I --> J[验证并更新特征库] ``` --- ### **4. 智能修复关键技术** #### (1) DOM树模糊匹配算法 ```python def find_similar_element(target, dom_tree): similarity_scores = [] for node in dom_tree: score = 0 # 属性相似度计算 score += calculate_attribute_similarity(target.attrs, node.attrs) # 结构相似度计算 score += 0.3 * calculate_structure_similarity(target.xpath, node.xpath) # 文本相似度计算 if target.text and node.text: score += 0.2 * fuzz.ratio(target.text, node.text) similarity_scores.append((node, score)) return max(similarity_scores, key=lambda x: x[1]) ``` #### (2) 视觉定位补偿机制 - 使用OpenCV进行模板匹配 - 结合SIFT特征点检测 - 动态ROI(Region of Interest)区域追踪 --- ### **5. 自愈效果验证** 建立**双重验证机制**: 1. 行为验证:执行click()后检测页面跳转状态 2. 视觉验证:截图比对元素交互前后变化 3. 日志记录示例: ``` [2023-12-20 14:30:45] WARNING - 元素"login_btn"定位失败 [2023-12-20 14:30:47] INFO - 启用备用XPath定位成功 [2023-12-20 14:30:48] SUCCESS - 新定位策略已存入特征库 ``` --- ### **6. 持续学习机制** - 建立定位策略知识库 - 使用决策树算法优化属性权重 - 定期生成元素稳定性报告: ```markdown | 元素名称 | 原始定位成功率 | 自愈后成功率 | 主要失效原因 | |------------|----------------|--------------|------------------| | 搜索框 | 78% | 97% | 动态ID变化 | | 购物车图标 | 92% | 99% | 页面加载延迟 | ``` --- ### **最佳实践建议** 1. 对高频变更元素设置**监控阈值**(如每周失效超过3次则触发告警) 2. 结合**代码版本管理**关联元素变更记录 3. 移动端需额外考虑: - 屏幕分辨率自适应 - 横竖屏切换补偿 - 平台特异性属性(iOS的accessibilityIdentifier) 通过这种设计,某金融APP测试脚本的维护成本降低了65%,元素定位稳定性从82%提升至98%。关键是要在定位策略灵活性和执行效率之间找到平衡点。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值