Appium 划出界面后找不到元素,如何统计超出界面的列表元素数量?

醋精测试媛 · 2021年04月15日 · 最后由 木月 回复于 2021年05月14日 · 4187 次阅读

这是一个手机 app 里面常见的划动型的列表,如果元素划出界面后,将无法定位,但是如果要统计元素的数量,则要先把当前的元素记录下来,然后保证滑动后当前元素将不会出现在界面上,还要保证不划出太多,以免有的元素未被包含在里面。

因为另一个页面会显示列表的长度,所以这个功能我觉得还是要做的。我目前的做法是通过不断的尝试找到一个合适的划动位置,比如从某个元素滑到另一个元素上,但是一个是,不一定有这么准确的元素,另一个是,自动化测试时间会被大大拉长,而且换一个型号的手机不知道还准不准确。

我也有想过根据文本信息来判断,但是列表中可以出现两个一样的信息,所以存在风险。

请问大家有遇到过这种问题吗,是如何解决的?

共收到 22 条回复 时间 点赞

你的目标是在列表中,目标 item 不再界面上怎么找到?列表元素数量不好统计的,有些是无线循环滚动

cmlanche 回复

是的,发现划出去就定位不到了,是不是这样比较难实现?

滚动到最后,可以通过再往下拉,如果还是和当前页面一致,则不再划动。但是总的来说,这样做非常耗时间。所以目前比较迷茫的两个点:
1.这个功能需要放到自动化测试里面吗?如果放,有没有比较简单的方法可以实现的?

2.这个功能如果要手动测试中检查,好像也很不简单,因为列表可能有 60 多条,人一个一个去看也不现实。

方案一:往指定方向滚动,每滚动一次就查找一次界面,如果没找到,则继续滚动,如果连续两次滚动找到的整体页面数据一样(比如统计所有文本),那么则认为滚动到尽头了,此时折回滚动。
方案二:在界面上找可以决定滚动多少的关键控件,比如序号,或者列表 item 中的索引值,根据自己要找的内容,大致判断需要滚动多少次。

方案一是普适的自动化方式,我目前做的框架就是这种,方案二比较适合具体的业务场景,意思就是说这个滚动查找的逻辑只适用这个页面,到其他页面就没法用了

这种为啥要前端去统计数据呀。。。没搞懂。。ui 自动化不是验证功能吗。。统计数据啥的交给接口呀

cmlanche 回复

我也是您说的方法一,问题是如何保证每一次滚动,滚动后的页面元素正好是滚动前的元素后面的元素?

不然会统计到重复或者遗漏元素,而且由于列表会出现相同的文本,所以无法以文本作标记。

咸鱼菜鸡 回复

前端有一个页面显示了列表的总条数,而且点击后会转到列表页,用不用去看列表中的数据是否和前一页中的统计数一致呢?

我觉得真没必要,如果你要判断这些 那你 ui 自动化要判断的东西也太多了,比如说页面上所有的控件显示是否正常这种,我个人还是觉得 ui 自动化只做功能验证就行。至于显示这种应该交给更好实现的方式去做,比如手动或者接口

咸鱼菜鸡 回复

好的,谢谢。我之前在想不做这个地方,但是考虑到手动测也不容易 ,因为列表行数很多。所以想着用自动化。

定义一个坐标滑动的,保证每个步长滑动距离是一行,然后做循环;不过就像上面说的不建议 UI 自动化统计列表数量

根据我的经验,这种数据展示一般是后端给的,前端只负责展示。所以验证了接口的正确性后,只需要手动验证一遍前端即可。之后除非有对应的代码变动,否则我都觉得不用再看了。

这个我很久之前尝试过,主要就是我会先获取当前页面的这个列表数量,然后获取到当前页面最后一行列表的一些信息(index),然后开始滑动,等到这个列表滑动到 index 为 1 或者为 0 的时候停止,再获取一次此时页面最后一行的列表的信息,循环进行前面的操作...最后进行统计...
我之前做的逻辑就是这样的,也能准确统计出数据

牧沐来了 回复

等到这个列表滑动到 index 为 1 或者为 0 的时候停止

请问这个是如何做到的呢?使用的是什么?

首先可以获取当前页面的列表的数量,然后我根据数量确认最后一个列表的 index 值,然后根据这个反向获取到这个列表的 ID 或者 DESC、TEXT 等值,这时候我会根据控件的大小进行像素点的滑动,每次滑动距离是列表宽度的一半,然后不停的检测此时这个列表的 index 值,如果是 1 或者 0 了就不滑了...最后就是滑动到最后一个列表的 index 值不会再变化为止
这个本来就没有太大的意义,当时也是我们一个领导提出的需求,当时想了很久才想到这个办法

建议先了解下开发是怎么实现的?

一般这种每一行的元素是重复的滑动控件,每一行的子控件是复用的。进入页面时根据控件大小申请对应的子控件对象数量,子控件在界面显示范围内消失后直接根据数据源更换里面的显示内容,再重新显示出来,减少重复申请释放对象消耗的时间。这个和 web 内部始终会记录完整 dom 树是不大一样的。

如果如你所说前一页显示列表长度,下一页显示具体列表,一般实现方式是第一页的长度是直接服务端返回的,不会是根据列表页实际内容计算长度(因为这个时候没必要显示列表内容,所以没必要拿数据量很大的列表页内容,而且还有可能遇到列表页数据分页,一次请求拿不到全部数据)。

如果采用的确实是这种实现,从原理上是会有一定概率前一个页面的长度显示和具体列表不一致的(比如在长度显示用的接口请求完毕到进入列表页这个时间间隔里,有其他用户修改了列表页内容,导致长度发生了变化),所以这个校验就算不通过也不能说一定有 bug。

跟你那个如何知道轮播图片数量是同个问题,解决任一个就等于也解决了另一个

陈恒捷 回复

谢谢。

(比如在长度显示用的接口请求完毕到进入列表页这个时间间隔里,有其他用户修改了列表页内容,导致长度发生了变化)

我现在已经没有计算列表元素数量了,而是尝试去增加,删除,看新增的元素是否出现,删除的元素是否消失来校验这个功能。我想如果可以增加/删除成功,应该说明它从服务器拉取的数据是正确的,实际上用户也不会太执着于去看这个总数,而是通过自己能够实现基本的功能来看 app 是否好用。

有点疑惑你想要校验的功能是什么?增加和删除元素后,列表是否能正常刷新展示最新数据?

我想如果可以增加/删除成功,应该说明它从服务器拉取的数据是正确的

你这个是纯 UI 自动化,只能看到用户看到的东西么?想校验拉取数据是否正确,我理解可以考虑加一个调用服务端接口或者直接查数据库的操作,然后比对下前几个内容是否一致,这样是不是效率更高、目标更纯粹呢?

通过增加删除来校验,有好处也有缺点。好处是一条用例把增删查都测完了,通过率高的话确实效率是有提升的,用例数量也少。缺点是把读和写混在一起了,会引起出问题的可能原因增加了,稳定性会降低,排查定位成本也会增加一些。比如如果出了问题导致读的内容不对,有可能是写的时候出问题,也可能是读的时候出问题,得人工另外排查。

陈恒捷 回复
  1. 是纯 UI 自动化,只能校验看得到的东西
  2. 我有调用接口,它是有两个页面,主页展示列表总数,详情页展示列表,我刚开始想校验列表中的总数是否与主页显示一致(并且疑惑是否要实现)
  3. 我想应该没必要担心读写混合的问题,因为正常的增加/删除用例中,步骤都是: a. 增加; b. 查看元素是否增加成功。 本来就是需要查看列表中是否增加成功,而且我没有尝试去读所有数据,因为会遇到题中的问题
  4. 我觉得如果增加删除可以成功,说明它使用的接口是没问题的,那么我只需要后续进行接口测试,来看接口的返回是否正确即可,我是这么想的

一看就知道你用的不是 uiautomator 2.0 框架,谁用都说好,你的这些问题都不是问题,都有现成 api

木月 回复

帖子的主题是 appium。

请问 uiautomator 2.0 框架中如何获取到当前的问题,appium 里面也有,但是我发现有很多不太好用的地方,比如:https://testerhome.com/topics/27597

第一种,纯原生 API

public UiObject findObjectInListView(String ListViewType, String ListViewValue, String text){
        /**
         * 定位元素,从列表中找到指定文本的元素对象
         */
        UiScrollable list =findListViewObject(ListViewType,ListViewValue);
        list.setMaxSearchSwipes(20);
        UiObject target=null;
        try {
            target = list.getChildByText(new UiSelector().className("android.widget.TextView"),text,true);
        } catch (UiObjectNotFoundException e) {
            e.printStackTrace();
            FailedCase.interruptProcess(String.format("UiObjectNotFoundException with value:%s",text));
        }
        return target;
    }

要求 App 本身翻页做的比较顺滑,就是预加载功能靠谱,不然容易中断,框架认为列表到底了,不再查找了,你还没加载出来新数据呢

第二种,翻页使用另一个 api 替代

UiScrollable list =findListViewObject(ListViewType,ListViewValue);
list.scrollForward(20);

剩下的就只是查找当前页面元素就可以了

你使用 uiautomator 碰到的问题,是因为没有设置滑动方向吧,默认是上下的,你要左右,要设置下

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册