app启动页数秒加载 代码_干货 | App 自动化测试痛点(弹框及首页启动加载完成判断处理)
1. 常见痛点
App 自动化测试中有些常见痛点问题,如果框架不能很好的处理,就可能出现元素定位超时找不到的情况,自动化也就被打断终止了。很容易打消做自动化的热情,导致从入门到放弃。比如下面的两个问题:
一是 App 启动加载时间较久(可能 App 本身加载慢,可能移动设备本身加载应用速度慢,也可能首页广告时间较长)。
另一个是各种弹框的出现,广告弹框,升级弹框,评价弹框等。在框架中如果不能处理好上面的情况,
以雪球 App 出现的几种弹框举例:
弹框一:
弹框二:
弹框三:
2、弹框处理
2.1 处理方向
- 弹框的影响范围弹框对我们自动化的影响主要是用例执行的打断,而至于弹框中广告内容的跳转或评价信息填写等属于另外的测试,因此我们主要是要将弹框处理消失,使应用回到用例执行的 PO;
- 弹框的消失方式观察弹框,我们会发现一般为了保证用户体验,弹框都会方便用户进行一键消除,例如上述中雪球的各种弹框,可能点击一个叉号,可能任意点击其他地方,或者评价框这种直接点击“下次再说”等。
- 弹框的处理效果自动化执行的任何时候,任意的弹框都可能出现,在这个时候用例不能失败,需要将对应的弹框正确处理后继续执行原用例,原用例的执行过程不受影响。
2.2 处理思路与实操
2.2.1 循环判断
1. 将需要处理的弹框元素加入到一个黑名单List中,遍历List,通过findElements方法得到的List大小来判断弹框元素是否存在,存在即点击处理
public static void handleAlert(){ List alertBox = new ArrayList<>(); alertBox.add(By.id("ib_close")); //广告弹框 alertBox.add(By.id("md_buttonDefaultNegative")); //评价弹框 alertBox.forEach(alert->{ By adsLocator = alert; List 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 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 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 自动化测试时的老大难问题。搞定了弹框及首页启动时加载完成如何判断处理。
(文章来源于霍格沃兹测试学院)
app启动页数秒加载 代码_干货 | App 自动化测试痛点(弹框及首页启动加载完成判断处理)相关推荐
- android自动化测试弹框,干货 | App 自动化测试痛点(弹框及首页启动加载完成判断处理)...
原标题:干货 | App 自动化测试痛点(弹框及首页启动加载完成判断处理) 1. 常见痛点 App 自动化测试中有些常见痛点问题,如果框架不能很好的处理,就可能出现元素定位超时找不到的情况,自动化也就 ...
- app启动页数秒加载 代码_iOS 底层探索 - 应用加载
一.前导知识 以下参考自 WWDC 2016 Optimizing App Startup Time : 1.1 Mach-O Mach-O is a bunch of file types for ...
- app启动页自动跳转源码_关于移动端App启动页的策划方案
App启动页是指app在启东时需要加载必要的运行环境和配置,在这个过程中提示用户等待的一个过渡页面. 在产品经理眼里启动页是app给予用户重要的第一印象:也是App最重要的黄金页面之一,所有用户100 ...
- 一个常用的自定义弹框封装(适配 AndroidX),加载 ProgressDialog,状态显示的 StatusDialog 和自定义 Toast,全部支持背景颜色,圆角,边框和文字的自定义,构建者模
MNProgressHUD 项目地址:maning0303/MNProgressHUD 简介: 一个常用的自定义弹框封装(适配 AndroidX),加载 ProgressDialog,状态显示的 S ...
- 动态启动页用gif能实现吗_[前沿科技] 微信启动页变脸的背后,你可知背后的秘密?...
日前,为庆祝"风云四号"正式交付用户投入使用,微信启动页开始"变脸",由此前的JPG静态图换成了GIF动态图片,这也是微信6年来首次"换脸" ...
- android启动页广告图,一张图搞定APP启动页广告
之前我们产品里的启动页比较简单,就是背景色加上我们的logo.slogan等,这种形式适配起来比较容易,把元素切出来交给开发写出来就行.最近由于运营的需求,我们需要在APP启动页展示广告,广告图更新频 ...
- 判断质数和合数python代码_「质数和合数」C语言:质数和合数的判断 - 金橙教程网...
质数和合数 给定一个正整数 n (2 <= n < 10000),判断是否为质数. 多组输入,每行一个 n (2 <= n <= 10000). 对于每一组数,如果是质数则输出 ...
- android筛选功能代码,Android中 TeaScreenPopupWindow多类型筛选弹框功能的实例代码
Github地址 YangsBryant/TeaScreenPopupWindow (Github排版比较好,建议进入这里查看详情,如果觉得好,点个star吧!) 引入module allprojec ...
- app启动页自动跳转源码_Jenkins集成appium自动化测试(Windows篇)
一,引入问题 自动化测试脚本绝大部分用于回归测试,这就需要制定执行策略,如每天.代码更新后.项目上线前定时执行,才能达到最好的效果,这时就需要进行Jenkins集成. 不像web UI自动化测试可以使 ...
最新文章
- 《易学C++(第2版)》——1.4 C++能够做些什么
- 自定义Kettle数据库插件
- 智能合约开发环境搭建及 Hello World 合约
- android/IOS SDK怎么判断用户是否安装了微信/QQ
- JavaEE5 Jax-ws 学习(Soap webservice)
- Dreamoon and Ranking Collection CodeForces - 1330A (贪心)
- ionic day01教程第一天之多平台运行(ios android)
- java structs hibernate php_eclipse+hibernate+structs 环境搭建
- python consul
- 1月5日 char **argv是什么用法啊?
- html水平制表和垂直制表,将水平制表符转换为垂直制表符(仅限HTML和CSS,无js)
- 基于simulink的16QAM仿真模型
- 遥感解译结果(多要素)用Arcgis做拓扑检查
- 《你是三月的小桨》光剑
- 两场直播丨易鲸捷分布式数据库的并发控制 、PostgreSQL日常工作分享
- python爬虫-抓取内涵吧内涵段子
- 2021.1知识图谱表示与推理综述(自己总结)
- 使用POI和EasyExcel实现Excel导入和导出功能
- 容联云聚客SCRM如何破SCRM保险应用困局
- 音乐播放器的滚动歌词的实现
热门文章
- java栈存储_【转载】Java中的数据存储(堆、栈、常量池)
- 低功耗蓝牙onscanresult 出来名字为空_浅析BLE5.0蓝牙模块在智能家居的运用
- 清华大学计算机专业学生埃朗读村,《朗读者~矣晓沅(清华大学计算机研究生 彝族)》...
- mac nginx apache mysql php 一键_Mac 下搭建 apache / nginx+php+mysql
- 奇奇seo优化软件_信阳seo优化排名软件
- python中文件分类_python实现根据文件格式分类
- 可视化图表种类还不清楚?快来看看这两个宝藏网站吧~~
- 用Python轻松开发数据库取数下载工具
- 外包程序员入职蚂蚁金服被质疑,网友:人生污点
- 25岁,在一个需要工作的周末……