Appium 在 Appium 中快速单击控件的变通方法

网球王子 · 2017年03月15日 · 最后由 Judy123LD 回复于 2020年04月05日 · 2229 次阅读

为什么需要快速点击控件
在我要测试的 APP 中,有一个名曰 “秘密花园” 的玩意儿,里面可以切换 正式、灰度、测试 环境;因为不想让用户随便就可以点进去切环境,开发同学在正常界面的某个位置放了一个控件(由于是保密的,所以这个位置点我就不公布了 😆 😇 ),必须快速单击这个控件 5 次,才能进入(咒语很简单😈 👿 )仅供测试时候使用;所以在自动化测试的时候,必须实现这个快速单击 5 次的动作。

踩坑
既然是连续单击 5 次,常规方法就是循环 里面套上 5 次 click;尝试之后不成功,于是打印一下 click 时间,吓了一跳;
具体代码和输出结果如下:

WebElement secret = driver.findElementByXPath("//android.view.View[contains(@resource-id,'id/touch')]");
for(int i = 1; i <= 5; i++) {
    long start = System.currentTimeMillis();
    secret.click();
    long end = System.currentTimeMillis();

    long duration = end - start;
    System.out.println("页面View对象单击: 第 " + i + " 次, 耗时: " + duration + "毫秒 !");
}

输出结果如下:
页面 View 对象单击: 第 1 次, 耗时: 3636 毫秒 !
页面 View 对象单击: 第 2 次, 耗时: 3160 毫秒 !
页面 View 对象单击: 第 3 次, 耗时: 3157 毫秒 !
页面 View 对象单击: 第 4 次, 耗时: 3159 毫秒 !
页面 View 对象单击: 第 5 次, 耗时: 3146 毫秒 !

可见虽然是连续 5 次的单击,但是每次单击的耗时要 3 秒以上,其实已经不能算是 5 次快速单击了,只是 5 次有充足间隔的单击;

分析
很明显 对象.click() 格式的单击调用一次会比较耗时,而秘密花园的进入条件是 5 次连续单击,研发代码控制的单击间隔时间在 300 毫秒以下才被认为是连续;

变通
如果用 对象.click() 调用有时间太长的问题,就必须换一种单击方法,屏幕坐标点单击 driver.tap() ;
思路:

  1. 获取单击对象左上角 x 轴坐标;
  2. 获取单击对象左上角 y 轴坐标;
  3. 单击对象左上角往右 往下 挪 10 个像素的点位(x+10, y+10)基本可以肯定这个点一定会落在对象有效范围内;
  4. 循环坐标点单击 5 次;
  5. 记录每次单击后的耗时;

看代码:

WebElement secret = driver.findElementByXPath("//android.view.View[contains(@resource-id,'id/touch')]");
int x = secret.getLocation().getX(); //获取对象左上角的x点坐标
int y = secret.getLocation().getY(); //获取对象左上角的y点坐标

for(int i = 1; i <= 5; i++) {
    long start = System.currentTimeMillis();
    driver.tap(1, x+10, y+10, 0);
    long end = System.currentTimeMillis();

    long duration = end - start;
    System.out.println("屏幕点直接单击: 第 " + i + " 次, 耗时: " + duration + "毫秒 !");
}

看输出结果:
屏幕点直接单击: 第 1 次, 耗时: 73 毫秒 !
屏幕点直接单击: 第 2 次, 耗时: 39 毫秒 !
屏幕点直接单击: 第 3 次, 耗时: 37 毫秒 !
屏幕点直接单击: 第 4 次, 耗时: 40 毫秒 !
屏幕点直接单击: 第 5 次, 耗时: 42 毫秒 !

总结
可以看出用 driver.tap() 调用的每次单击耗时明显减少,如果需要有快速单击控件的需求可以用这种方法做变通。

共收到 6 条回复 时间 点赞

这是因为对象的 click 方法,其实是先去递归搜索这个控件,然后再点击,肯定没有直接点击坐标快。

—— 来自 TesterHome 官方 安卓客户端

Crazyerick 回复

对,代码遍历的东西少了自然就快很多

我也发现 click() 确实很难连击,多谢楼主对问题的深挖!

我的依赖是 java-client 6.0,怎么没有 driver.tap() 这个方法呢,用的 appium-client 1.6.1

iOS 目前是没有问题的,但是 Android 还有问题

def tap_el(self, element, times: int):
    """
    单击某个控件N次
    :param element: 要单击的控件
    :param times: 要单击的次数
    :return:
    """
    def _center_rect(r):
        # center_x = r['x'] + r['width'] / 2.0
        # center_y = r['y'] + r['height'] / 2.0
        center_x = r['width'] / 2.0
        center_y = r['height'] / 2.0
        return center_x, center_y

    rect = element.rect
    # HTNone 的设计缺陷导致不能准确的识别有效元素
    # 后期可能去掉HTNone
    if isinstance(rect, bool):
        return

    action = TouchAction(self)
    center = _center_rect(element.rect)
    action.tap(element=element,
               x=center[0],
               y=center[1],
               count=times).perform()
Yvan 回复

你好,我也没有 driver.tap() 这个方法,请问解决了吗

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