干货 | 解决 App 自动化测试的常见痛点(弹框及首页启动加载完成判断处理)

news2024/11/12 22:12:30

1. 常见痛点

App 自动化测试中有些常见痛点问题,如果框架不能很好的处理,就可能出现元素定位超时找不到的情况,自动化也就被打断终止了。很容易打消做自动化的热情,导致从入门到放弃。比如下面的两个问题:

一是 App 启动加载时间较久(可能 App 本身加载慢,可能移动设备本身加载应用速度慢,也可能首页广告时间较长)。

另一个是各种弹框的出现,广告弹框,升级弹框,评价弹框等。在框架中如果不能处理好上面的情况,

以雪球 App 出现的几种弹框举例:

弹框一:

弹框二:

弹框三:

2、弹框处理

2.1 处理方向

  • 弹框的影响范围

弹框对我们自动化的影响主要是用例执行的打断,而至于弹框中广告内容的跳转或评价信息填写等属于另外的测试,因此我们主要是要将弹框处理消失,使应用回到用例执行的 PO;

  • 弹框的消失方式

观察弹框,我们会发现一般为了保证用户体验,弹框都会方便用户进行一键消除,例如上述中雪球的各种弹框,可能点击一个叉号,可能任意点击其他地方,或者评价框这种直接点击“下次再说”等。

  • 弹框的处理效果

自动化执行的任何时候,任意的弹框都可能出现,在这个时候用例不能失败,需要将对应的弹框正确处理后继续执行原用例,原用例的执行过程不受影响。

2.2 处理思路与实操

2.2.1 循环判断

1. 将需要处理的弹框元素加入到一个黑名单List中,遍历List,通过findElements方法得到的List大小来判断弹框元素是否存在,存在即点击处理

public static void handleAlert(){        List<By> alertBox = new ArrayList<>();        alertBox.add(By.id("ib_close"));   //广告弹框        alertBox.add(By.id("md_buttonDefaultNegative")); //评价弹框        alertBox.forEach(alert->{            By adsLocator = alert;            List<WebElement> ads = driver.findElements(adsLocator);            if (ads.size() >= 1) {                ads.get(0).click();            }        });    }

2. 将handleAlert()方法加到driver.findElement方法之前,使定位前先判断弹框的存在与否并进行处理

public static WebElement findElement(By by) { System.out.println(by); handleAlert(); return driver.findElement(by); }

上述方法初步解决了弹框问题,但是缺点也很明显。

缺点:每次定位元素前都需要处理弹框,影响执行效率,速度较慢 因此我们引入try catch来解决此问题

2.2.2 try catch 提升效率

我们利用try catch的异常捕获处理的机制,让元素仅在定位失败时才进入弹框处理handleAlert()方法,处理完毕后重新返回driver.findElement(by),对原case元素继续进行定位执行;这样就大大提升了处理效率,使处理更为精准。

public static WebElement findElement(By by) { try { System.out.println(by); return driver.findElement(by); } catch (Exception e) { System.out.println("进入弹框处理"); handleAlert(); return driver.findElement(by); } }

递归处理:

一般情况下我们一次只会出现一个弹框,但是例外的是可能有一个以上的弹框同时出现,这样的话虽然处理了其中一个弹框,但是剩下的弹框依然会阻断用例的正常执行,这个时候就可以使用递归的方法,在处理完弹框后返回findElement方法自身,继续进行try catch,使之进入弹框处理逻辑

public static WebElement findElement(By by) { try { System.out.println(by); return driver.findElement(by); } catch (Exception e) { System.out.println("进入弹框处理"); handleAlert(); return findElement(by); } }

注意:

使用递归方法后有一个问题,就是假如并不是因为某个弹框的出现而导致的定位失败,而这个时候通过try catch进入到弹框处理逻辑后,由于并未匹配到弹框元素,所以递归就会进入一个死循环,不断重复着弹框处理的逻辑,所以使用递归时我们也需要对其次数进行限制;一般两个弹框同时出现已经算多的了,所以建议可以将递归的次数限制到最多两次便退出。

static int i = 1;public static WebElement findElement(By by) { try { System.out.println(by); return driver.findElement(by); } catch (Exception e) { if (i > 2){ //设置最多递归两次 i = 1; return driver.findElement(by); } System.out.println("进入弹框处理第"+i+"次"); handleAlert(); i++; return findElement(by); //最后调用自身完成递归,防止多弹框同时出现造成定位失败 }}

2.2.3 PageSource助力效率再提升

按照上面的方法,看似已经很好的解决了弹框的处理,但是可以注意到的是:

  • 在检查弹框的时候依然使用的是appium的定位,在当前页面中根据元素的属性去一一查找定位

  • 所有的黑名单中的弹框都会被定位查找一遍

而我们实际中最想要的也是最有效率的方法应该是:

  • 只有在当前页面中存在的弹框才对其进行定位、操作、处理。为了达到我们想要的效果,就需要借助于PageSource了。

1)appium的driver提供了一个getPageSource方法,此方法可以在当前页面可以得到一个文本字符串,也可以理解为当前页面的xml,我们利用这种xml文本来进行判断,就比用appium一一定位的方式要快速和精准的多了

String pageSource = driver.getPageSource();

2)设置黑名单,黑名单要使用元素的xpath,用来和PageSource文本做匹配,判断此弹框是否存在当前页面

String adBox = "com.xueqiu.android:id/ib_close";String gesturePromptBox = "com.xueqiu.android:id/snb_tip_text";String evaluateBox = "com.xueqiu.android:id/md_buttonDefaultNegative";

3)我们将黑名单中的 xpath作为弹框查找的标记符,另外再定义一个定位符,用来找到弹框后做定位处理使用;这里可以将标记符和定位符存入HashMap中

HashMap<String,By> map = new HashMap<>();map.put(adBox,By.id("ib_close"));map.put(gesturePromptBox,By.id("snb_tip_text"));map.put(evaluateBox,By.id("md_buttonDefaultNegative"));

4)遍历map,判断黑名单弹框元素是否存在于当前pageSource,存在即根据弹框处理方式进行点击或其他操作(如上述中的新功能提示弹框,点击弹框自身无法消除,需点击页面其余部分方可消除)处理

map.entrySet().forEach(entry ->{ if (pageSource.contains(entry.getKey())){ if (entry.getKey().equals("com.xueqiu.android:id/snb_tip_text")){ System.out.println("gesturePromptBox found"); Dimension size = driver.manage().window().getSize(); //点击屏幕的中心位置,消除新功能提示弹框 new TouchAction<>(driver).tap(PointOption.point(size.width/2,size.height/2)).perform(); }else { //其余弹框直接点击消除 driver.findElement(entry.getValue()).click(); } }});

5)最后有一个小技巧,临时修改隐式等待时间,防止查找黑名单中元素过久,在弹框处理结束后再讲隐式等待时间复原;完整的方法实现如下:

//很多弹框的话,最好的是直接定位到到底哪个弹框在界面上,元素的判断使用xpath    public static void handleAlertByPageSource(){        String pageSource = driver.getPageSource();//可以得到一个文本字符串,也可以理解为当前页面的xml        //黑名单        String adBox = "com.xueqiu.android:id/ib_close";        String gesturePromptBox = "com.xueqiu.android:id/snb_tip_text";        String evaluateBox = "com.xueqiu.android:id/md_buttonDefaultNegative";        //将标记和定位符存入map        HashMap<String,By> map = new HashMap<>();        map.put(adBox,By.id("ib_close"));        map.put(gesturePromptBox,By.id("snb_tip_text"));        map.put(evaluateBox,By.id("md_buttonDefaultNegative"));        //临时修改隐式等待时间,防止查找黑名单中元素过久        driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);        //遍历map,判断黑名单弹框元素是否存在于当前pageSource,存在即点击处理        map.entrySet().forEach(entry ->{            if (pageSource.contains(entry.getKey())){                if (entry.getKey().equals("com.xueqiu.android:id/snb_tip_text")){                    System.out.println("gesturePromptBox found");                    Dimension size = driver.manage().window().getSize();                    new TouchAction<>(driver).tap(PointOption.point(size.width/2,size.height/2)).perform();                }else {                    driver.findElement(entry.getValue()).click();                }            }        });        //判断完成后将隐式等待时间恢复        driver.manage().timeouts().implicitlyWait(8,TimeUnit.SECONDS);    }

6)最后将findElement方法中的handleAlert方法替换为handleAlertByPageSource方法即可

static int i = 1;public static WebElement findElement(By by) { try { System.out.println(by); return driver.findElement(by); } catch (Exception e) { if (i > 2){ //设置最多递归两次 i = 1; return driver.findElement(by); } System.out.println("进入弹框处理第"+i+"次"); handleAlertByPageSource(); i++; return findElement(by); //最后调用自身完成递归,防止多弹框同时出现造成定位失败 }}

3. 首页判断

再来解决首页加载时可能出现的坑。

App 启动加载时间较久(可能 App 本身加载慢,也可能是移动设备本身加载应用速度慢,也可能首页广告时间较长),导致定位超时,用例失败。对此我们又如下两步解决办法。

3.1 首页元素显示等待

如标题所述,对首页进入使用显示等待,利用搜索控件的出现来判断是否进入了首页,这样不影响其他元素隐式等待的时间,也解决了首页初始化加载时间过长的问题。

例如雪球仅在进入首页后会出现 id为user_profile_container的用户信息控件,那么我们就可以以此为依据来判断应用是否加载完成进入了首页。

在启动方法中加入显示等待上述首页控件 30 秒,到控件可被定位时确认进入首页。

new WebDriverWait(driver,30) .until(ExpectedConditions.visibilityOfElementLocated(By.id("user_profile_container")));

缺点:

但是这样有个情况不能解决:若加载完成后有弹框出现,可能就一直无法定位到首页元素,但是实际上已经加载完成,比如下图的首页广告弹框 。

3.2 首页弹框判断

文章第二部分介绍了利用 PageSource 来判断弹框是否存在的方法,在这里依然适用,还是熟悉的味道,还是同样的套路,将弹框元素 xpath 也加入 PageSource 判断,这样无论首页控件和首页弹框哪一个被发现,就都可以判断应用已经加载完成,成功进入首页,剩下的就可以交给用例和其他处理逻辑了

new WebDriverWait(driver,30) .until(x ->{ String xml = driver.getPageSource(); Boolean checkResult = xml.contains("user_profile_container") || xml.contains("com.xueqiu.android:id/ib_close"); System.out.println("主页元素查找的结果是:" + checkResult); return checkResult; });

3.3 运行效果展示

好了,经过上面的分析之后,我们终于搞定了入门 APP 自动化测试时的老大难问题。搞定了弹框及首页启动时加载完成如何判断处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/141485.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【代码题】链表面试题

目录 1.链表分割 2.相交链表 3.环形链表 4.环形链表 II 1.链表分割 点击进入该题 现有一链表的头指针 ListNode* pHead&#xff0c;给一定值x&#xff0c;编写一段代码将所有小于x的结点排在其余结点之前&#xff0c;且不能改变原来的数据顺序&#xff0c;返回重新排列后的…

国内注册Steam账号的快捷方法

本文介绍在国内注册Steam账号的快速、简便方法。 目前&#xff0c;在国内注册新的Steam账号变得越来越麻烦&#xff1b;尤其在最近&#xff0c;无论是无休止的谷歌人机身份验证&#xff0c;还是无法收到的验证邮件&#xff0c;都使得新建一个Steam账号与原来相比变得更加困难。…

[Linux_]make/Makefile

[Linux_]make/Makefile 心有所向&#xff0c;日复一日&#xff0c;必有精进专栏&#xff1a;《Linux_》作者&#xff1a;沂沐沐目录 [Linux]make/Makefile 前言 一、Mikefile 二、如何写Mikefile文件 三、原理 四、项目清理 报错&#xff1a;missing separator 前言 一个工…

Linux 命令

最基础的命令 1.我是谁 我用什么账号登录 whoami 2.我在那 在那个目录下 pwd 3.环顾四周 1.ll展示详细信息 2.ls 展示文件名称 4.cd 想去那 改变目录 cd 回家 cd ./ 定位到当前目录 cd../ 上级目录 cd../../上两级目录。 5.切换用户 su 从普通用户切换到root用户的…

C#应用程序配置文件(XML序列化) - 开源研究系列文章

上次写了一个C#线程池及管理器的博文( C#开发的线程池和管理器 - 开源研究系列文章 )&#xff0c;收到了不小的浏览量&#xff0c;在此感谢各位网友的支持。这次将另一个功能放出来单独讲解&#xff1a;C#应用程序的配置文件&#xff0c;使用的是XML文件保存程序的配置信息&…

数据结构(栈、队列、链表)

文章目录前言数据结构(栈、队列、链表)1、栈2、队列3、链表3.1、单向链表结构3.2、双向链表结构前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不易啊^ _ ^。   而且听说点赞的人每天的运气都不会太差&…

多边形点集排序

一、问题描述已知多边形点集P {P1, P2, ... , PN}&#xff0c;其排列顺序是杂乱&#xff0c;依次连接这N个点&#xff0c;无法形成确定的多边形&#xff0c;需要对点集P进行排序后&#xff0c;再绘制多边形。二、排序规则点集排序过程中&#xff0c;关键在于如何定义点的大小关…

STC32G 时钟系统

文章目录时钟系统代码配置总结时钟系统 系统时钟有4个时钟源可供选择&#xff1a; 内部高精度IRC内部32KHzIRC&#xff08;精度较低&#xff09;外部晶振内部PLL输出时钟 主要关心的是两个指标&#xff1a;SYSclk和HSCLK SYSclk是系统的时钟&#xff0c;决定了指令执行速度…

Android 深入系统完全讲解(三)

系统调用 操作系统提供了一些方法&#xff0c;让用户层可以调用&#xff0c;而为了安全起见&#xff0c;这些方法调用&#xff0c;都是在内核空间。于是&#xff0c;用户调用的时候&#xff0c;就会有个动作&#xff0c;叫做陷入内核。 当用户调用系统方法的时候&#xff0c;系…

【k8s-device plugin】如何编写 k8s device plugin

参考 Device Plugin 入门笔记&#xff08;一&#xff09; Device Plugin 入门笔记&#xff08;二&#xff09; 从零开始入门 K8s&#xff1a;GPU 管理和 Device Plugin 工作机制 Kubernetes开发知识–device-plugin的实现 https://github.com/oceanweave/cola-device-plugi…

基于springboot的智慧物业管理系统的设计与实现(前后端分离)

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

mysql 中间件 mycat2 的详细安装及配置步骤

下载 首先打开mycat官网&#xff1a;MyCat2 右上角下载里面有个文件下载服务&#xff0c;点进去发现无法访问 这里需要配置一下host&#xff0c;把下面内容复制到host文件中。host文件位置在C:\Windows\System32\drivers\etc 210.51.26.184 mycat.org.cn www.mycat.org.cn …

第五篇 - 数组的劫持

一&#xff0c;前言 上篇&#xff0c;主要介绍了 Vue 数据初始化流程中&#xff0c;对象属性的深层劫持是如何实现的 核心思路就是递归&#xff0c;主要流程如下&#xff1b; 1.通过 data isFunction(data) ? data.call(vm) : data;处理后的 data 一定是对象类型 2.通过 d…

如何定位Bug——Qt

1. 前言 在写程序的过程中&#xff0c;不可避免出现各种Bug&#xff0c;如何快速的定位到Bug的位置&#xff0c;是程序员必备的技能之一。 2. 几种方法 2.1. 逻辑分析 根据程序所出的问题&#xff0c;分析问题可能所在的几个位置&#xff0c;通过逻辑分析找出Bug&…

从 Nginx Ingress 窥探云原生网关选型

作者&#xff1a; 魁予 现今有越来越多的企业开始采纳云原生理念进行应用架构转型。而 K8s 和微服务是云原生的两大支柱&#xff0c;随着云原生浪潮而被广泛应用。 对多数应用而言&#xff0c;提供对外服务的使命并不会改变&#xff0c;相比于原来的单体应用&#xff0c;微服…

VUE3中,使用.env.development和.env.production

在实际项目开发过程中&#xff0c;可能开发环境和生产&#xff08;测试&#xff09;环境不一样&#xff0c;经常需要修改配置常量&#xff0c;才能满足对应的环境&#xff0c;才能使软件运行起来。在vue3中可以使用2个文件进行区分。 .env.development&#xff1a;开发环境 .…

Mysql存储引擎 初级(自用笔记)

内容来自于(https://www.bilibili.com/video/BV1Kr4y1i7ru?p58&vd_source3cf72bb393b8cc11b96c6d4bfbcbd890) 1.存储引擎 1.1Mysql体系结构 1.2什么是存储引擎呢? 存储引擎就是存储数据,建立索引,更新,查询数据等技术的实现方式. 存储引擎是基于表的,而不是基于数据库的…

魔兽世界开服教程wow服务器框架Trinirycore构建

首先明杰先给各位普及一下TrinityCore是什么TrinityCore 是c实现MMORPG框架来自MaNGOS&#xff0c;大型网络对象服务&#xff0c;随着时间的推移&#xff0c;该项目代码广泛的优化&#xff0c;改善和清理代码。需要准备的架设工具&#xff1a;端&#xff08;版本&#xff09;、…

皮尔逊相关性分析一文详解+python实例代码

目录 前言 一、数值类型 二、皮尔逊系数使用场景 二、皮尔逊相关系数(Pearson correlation) 1.定义 2.线性关系判定 3.正态检验 1.KS检验 4.计算代码 点关注&#xff0c;防走丢&#xff0c;如有纰漏之处&#xff0c;请留言指教&#xff0c;非常感谢 参阅 前言 相关性…

MySQL中这10个小玩意,让人眼前一亮

我最近几年用MYSQL数据库挺多的&#xff0c;发现了一些非常有用的小玩意&#xff0c;今天拿出来分享到大家&#xff0c;希望对你会有所帮助。 1.group_concat 在我们平常的工作中&#xff0c;使用group by进行分组的场景&#xff0c;是非常多的。 比如想统计出用户表中&…