上两篇文章介绍了自动遍历的测试需求、工具选择和 AppCrawler 的环境安装、启动及配置文件字段基本含义,这里将以实际案例更加细致的说明配置文件的用法和一些特殊场景的处理。
下面我们继续之前的例子,在雪球搜索框输入搜索内容后的页面开始:
yaml 写法如下:
testcase:
name: "XueQiuTestDemo AppCrawler"
steps:
- { xpath: "//*[contains(@resource-id,'image_cancel')]", action: click }
- xpath: home_search
action: click
- xpath: search_input_text
action: alibaba
- { xpath: 阿里巴巴, action: click }
我们先看demo配置文件中的原始写法,如下:
selectedList:
- given: []
when: null
then: []
xpath: "//*[contains(name(), 'Button')]"
action: null
actions: []
times: 0
- given: []
when: null
then: []
xpath: "//*[contains(name(), 'Text') and @clickable='true' and string-length(@text)<10]"
action: null
actions: []
times: 0
- given: []
when: null
then: []
xpath: "//*[@clickable='true']/*[contains(name(), 'Text') and string-length(@text)<10]"
action: null
actions: []
times: 0
- given: []
when: null
then: []
xpath: "//*[contains(name(), 'Image') and @clickable='true']"
action: null
actions: []
times: 0
- given: []
when: null
then: []
xpath: "//*[@clickable='true']/*[contains(name(), 'Image')]"
action: null
actions: []
times: 0
- given: []
when: null
then: []
xpath: "//*[contains(name(), 'Image') and @name!='']"
action: null
actions: []
times: 0
- given: []
when: null
then: []
xpath: "//*[contains(name(), 'Text') and @name!='' and string-length(@label)<10]"
action: null
actions: []
times: 0
原始文件中将所有可点击的控件类型都包括了进去,再加上了部分 text 长度的限制 现在我们按照自己平常的简便写法重新编写,先设置所有 clickable 等于 true 的控件进行点击:
selectedList:
- { xpath: "//*[@clickable='true']", action: click }
blackList:
- given: []
when: null
then: []
xpath: ".*[0-9]{2}.*"
action: null
actions: []
times: 0
我们现在希望不要点击到叉号
和取消按钮,否则会跳出此页面,那么就可以把其加入黑名单中,如下:
blackList:
- xpath: ".*[0-9]{2}.*"
- xpath: //*[@resource-id='action_delete_text']
- xpath: //*[@resource-id='action_close']
firstList:
- { xpath: "//*[contains(@text,'股票')]", action: click }
每个标签页下面对应着很多控件需要被操作,可是在当前页面下的控件未被遍历完的时候就有可能会点击到其他标签页中了,我们希望的是在一个标签页下完全遍历结束后最后再点击标签控件,这个就可以借助lastList来完成,让元素在点进标签页后的内容为最后遍历
lastList:
- { xpath: "//*[contains(@resource-id,'ti_tab_indicator')]//*", action: click }
因此我们可以给它设置一个默认的后退按钮,使所有事件完成后再 back
backButton:
- { xpath: "//*[contains(@resource-id,'action_back')]", action: click }
maxDepth: 2
findBy: "xpath"
有时候我们会遇见这种情况:设置了 clickable 未 true 的控件都被遍历,可是运行时发现很多控件都没有被遍历到,一般这种情况有一下两种原因:
在“股票”和“用户”tag页中,“加自选”和“关注”控件的clickable及id属性一样。
他们所属的页面属性也一样,所以会被看做是同一个页面下的同一个控件:
如上这种情况肯定不是我们想要的,我们想要它在股票和用户页都分别进行遍历,更好的覆盖测试,那么就要借助于 defineUrl 了;
1)按照上面的介绍,我们首先要找一个标志控件,用来做页面的区分,那么我们首先想到的就是从“股票”和“用户”这两个 tag 标签属性上来找,遗憾的是最终发现这两个控件的属性全都一毛一样:
2)接着我们就必须从 tag 页内部来找标志控件了,我们发现在“股票”和“用户”页中搜索出来的结果名称的 id 是不同的:
3)上面介绍过了 defineUrl 是取的 text 属性值作为标志区分,所以这里取股票页的第一个元素“阿里巴巴”和用户页的第二个元素“阿里巴巴四十大盗”, 具体 yaml 写法如下:
defineUrl:
- (//*[contains(@resource-id, "stockName")])[1]
- (//*[contains(@resource-id, "user_name")])[2]
缺点:上面的做法虽然解决了页面区分的问题,但是有一个缺点就是我们定义了遍历的深度,然而使用 defineUrl 之后将每个标志符在的页面都视为一个新的 activity,因此遍历深度就会从这里开始重新计算
4)继续解决上述的缺点,我们可以在 clickable 之前指定所属的页面,当判断不在此页面后就会自动跳回
selectedList:
- { xpath: "//*[@resource-id='com.xueqiu.android:id/ll_search_result']//*[@clickable='true']//*", action: click }
5)另外我们之前在 selectList 中写了 clickable=true, 而 clickable=true 通常只是布局元素,布局元素一般是没有任何属性的,不知道控件里包含什么,这样在截图和生成报告的时候就会造成不精准,截图中的步骤框就很可能选择错误,对我们定位分析问题造成困扰;
所以我们要继续往下找标志符,以 Text 作为定位标志符:
selectedList:
- { xpath: "//*[@resource-id='com.xueqiu.android:id/ll_search_result']//*[@clickable='true']//*[contains(@class,'Text')]", action: click }
用 Text 作为标志符以后所有的 Text 属性都会遍历一遍,还可以进一步优化,使用id非空作为判定条件,并且通常研发将控件设置 id 的话很可能此控件有关键的作用
selectedList:
- { xpath: "//*[@resource-id='com.xueqiu.android:id/ll_search_result']//*[@clickable='true']//*[@resource-id!='']", action: click }
6)按照上面的写法又引发了新的问题,就是 id 不为空的时候,我们的 tag 控件无法被选中了,因为 tag 控件的 id 正好为空:
因此我们又需要对 selectedList 进行修改,单独增加一条判定条件用来过滤出 tag 控件;我们注意到它们同属一片有 id 的区域,并且各自自身有 text:
修改后的selectedList如下:
selectedList:
- { xpath: "//*[@clickable='true']//*[contains(@class,'Text')]", action: click }
- { xpath: "//*[contains(@resource-id, 'ti_tab_indicator')]//*[contains(@class,'Text')]",
tagLimitMax: 1
缺点:这个设置是一个全局的,一旦设置,那么所有的同类型的控件都只会被点击一次,但是像上个例子中的 4 个tag标签控件虽然是同类型的,但是每一个都需要被点击一次,这样显然就不符合我们的需求了,这个时候就需要 tagLimit 参数了
tagLimit:
- xpath: //*[contains(@resource-id, 'ti_tab_indicator')]//*[contains(@class,'Text')]
action: click
times: 4
triggerActions:
- xpath: //*[contains(@resource-id,'image_cancel')]
action: click
times: 1
firstList[0]
firstList[1]
排除lastList firstList之后剩下的元素
lastList[0]
lastList[1]
backbutton
Main Main->UserProfile Main->UserProfile->Login Main maxDepth是判断这个堆栈最长的长度,一旦超过就回退
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。