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

我们下载 Docker 镜像的时候,默认会访问 Docker 网站,而 Docker 网站是在国外部署的,距离比较远下载速度特别慢。我们可以通过设置加速器的方式来加速 Docker 镜像下载的速度。下面将描述一下使用加速器的步骤:
1.我们这里选择的是阿里云提供的Docker 镜像加速器服务,首先访问阿里云的镜像仓库:https://cr.console.aliyun.com/(如果没有阿里云账号则需要注册)
2.选择“镜像加速器”
3.根据个人的系统平台,选择运行 Docker 的 OS,并按照操作文档的要求修改Docker 配置文件,然后重启 Docker 服务即可完成加速器的配置。

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

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

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

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

弹框一:

弹框二:

弹框三:

  • 弹框的影响范围
    • 弹框对我们自动化的影响主要是用例执行的打断,而至于弹框中广告内容的跳转或评价信息填写等属于另外的测试,因此我们主要是要将弹框处理消失,使应用回到用例执行的 PO;
  • 弹框的消失方式
    • 观察弹框,我们会发现一般为了保证用户体验,弹框都会方便用户进行一键消除,例如上述中雪球的各种弹框,可能点击一个叉号,可能任意点击其他地方,或者评价框这种直接点击“下次再说”等。
    • 弹框的处理效果
    • 自动化执行的任何时候,任意的弹框都可能出现,在这个时候用例不能失败,需要将对应的弹框正确处理后继续执行原用例,原用例的执行过程不受影响。
  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();
                                                                        }
                                                                                });
                                                                                    }
  1. 将handleAlert()方法加到driver.findElement方法之前,使定位前先判断弹框的存在与否并进行处理
  2. public static WebElement findElement(By by) {
  3.         System.out.println(by);
    
  4.         handleAlert();
    
  5.         return driver.findElement(by);
    
  6.         }
    


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

缺点:每次定位元素前都需要处理弹框,影响执行效率,速度较慢 因此我们引入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); //最后调用自身完成递归,防止多弹框同时出现造成定位失败
}
}



按照上面的方法,看似已经很好的解决了弹框的处理,但是可以注意到的是:
- 在检查弹框的时候依然使用的是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";

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();
                                                                                                  }
                                                                                                      }
                                                                                                      });
//很多弹框的话,最好的是直接定位到到底哪个弹框在界面上,元素的判断使用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); //最后调用自身完成递归,防止多弹框同时出现造成定位失败
                                                                                                                }
                                                                                                                }

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

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

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

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

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

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

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

文章第二部分介绍了利用 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;
                                                                                                                });

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

技能学习,站在高手/过来人的肩膀上,才能高效进阶。

对于想系统进阶提升测试开发技能的同学,推荐霍格沃兹测试学院出品的 《测试开发从入门到高级实战》系统进阶班课程。

4 个月由浅入深,强化集训,测试大咖思寒领衔亲授,通过 8+ 企业级项目实战演练,带你一站式掌握 BAT 测试开发工程师必备核心技能(对标阿里巴巴P6+,挑战年薪50W+)!学员直推 BAT 名企测试经理,普遍涨薪 50%+!

阅读

阅读

阅读

原文链接

获取更多相关资料+v~ ceshiren001
获取更多技术文章分享

Docker 的常用命令一般分为:镜像管理、容器管理。

查看 Docker 版本

docker version

下面使用 busybox 软件作为示例,busybox软件是一个集成了非常多最常用的 Linux 命令和工具的软件集合。

查看所有镜像

docker images

  • REPOSITORY:镜像来自哪个仓库
    • TAG:镜像的标签信息,版本之类的信息
    • IMAGE ID:镜像创建时的id
    • CREATED:镜像创建的时间
    • SIZE:镜像文件大小
  • 下载软件镜像
  • docker pull busybox:latest

• latest表示使用busybox软件的最新版本,所以软件默认下载都是 latest 版本。

导出镜像

docker save busybox > busybox.tar


• 把busybox镜像导出为 busybox.tar 文件,可以把 busybox.tar 文件复制到别的操作系统上使用,免除下载时网络慢的问题。

删除镜像

docker rmi busybox:latest


• 镜像一般都会根据版本打包,如果有下载一个软件的多个版本就需要指定具体版本信息。如 busybox:1.26 就会删除 busybox 软件的 1.26 版本的镜像,不会删除latest 版本的镜像。
导入镜像

docker load < busybox.tar


• 使用导出命令导出的镜像,可以通过此命令导入到没有下载此软件的操作系统,方便网络条件差的情况使用。
更改镜像名

docker tag busybox:latest busybox:test


• busybox:latest原镜像名,busybox:test要改成的镜像名



运行容器

docker run -d --name=busybox busybox:latest ping 114.114.114.114


• run:run参数代表启动容器
• -d:以后台daemon的方式运行
• --name:指定一个容器的名字,此后操作都需要使用这个名字来定位容器。
• busybox:latest:容器所使用的镜像名字
• ping 114.114.114.114:启动容器执行的命令

查看运行的容器

docker ps



查看所有容器

docker ps -a


- CONTAINER ID:容器启动的id
- - IMAGE:使用哪个镜像启动的容器
- - COMMAND:启动容器的命令
- - CREATED:创建容器的时间
- - STATUS:容器启动时间
- - PORTS:容器映射到宿主机的端口
- - NAMES:容器启动的名字
启动容器

docker start busybox



重新启动容器

docker restart busybox



停止容器

docker stop busybox



杀死容器

docker kill busybox



删除运行中的容器

docker rm -f busybox



执行容器内命令

docker exec -it busybox ls


• -it 交互终端

复制容器内文件

docker cp busybox:/etc/hosts hosts



查看容器日志

docker logs -f busybox



## 


⬇️ 点击“阅读原文”,提升测试核心竞争力!
[原文链接](https://mp.weixin.qq.com/s?__biz=MzU3NDM4ODEzMg==&mid=2247494470&idx=1&sn=3b7d2b46b964feab1959c0d1dd2dca10&chksm=fd31898dca46009b9831bbf7febaf59f0960db178f3f4451a70b88ceae641df167b9df5732dd#rd) 

获取更多相关资料+v~ ceshiren001
[获取更多技术文章分享](https://qrcode.ceba.ceshiren.com/link?name=article&project_id=qrcode&from=csdn2&timestamp=1651043895)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值