Appium 基于 appium 实现获取 ScrollView 和 UIATable 下所有列表元素

tbya · 2015年06月29日 · 最后由 Shandong Lanxiang 回复于 2015年07月08日 · 2578 次阅读

偶尔翻到几个帖子谈到 Android ScrollView 和 ios UIATable 如何获取所有子元素的问题. 正好最近写了个类似的东西, 随意拍砖..

背景

公司目前 UI 的自动化测试框架是基于 appium 搭建的, 各种封装以及分层就不谈了, 最主要的目的是让同一套自动化测试代码能同时运用在 android 和 ios 平台上 (基础是 app 在 Android 和 IOS 上的 UI 功能测试用例一致或极为类似).

思路

思路其实很简单, 基本就以下 2 点.

  • 初始读取元素列表后, 上下滑动再次获取列表, 并维护一个整体的元素列表.
  • 重写对象的 equals() 和 hashCode() 方法用来判断元素是否已经存在于全局列表中了.

代码

  • 首先代码中所见的 By, IMegaElement, app 等类均是经过封装或自行开发的类, 所以代码中均没有使用原生的对象.
  • 目前框架支持一套代码在 Android 和 iOS 上均可以运行, 所以代码中没有区分 Android 和 iOS.
  • 另外由于篇幅原因, 移除了部分代码, 例如 By 的类型只有 ById.
  • mListView 中有获取改节点下所有子节点的部分, 我们需要验证节点下所有 text 的正确性, 不需要的各位可以忽略掉.

经过分装的 ListView 对象


public mListView(By by) {
    super(by,mListView.class);

    rootPath = by.getParameter();

    //设置子节点路径
    if(by.getType().equalsIgnoreCase("ById")){
        String id = by.getParameter();
        childrenPath = "//*[@resource-id='"+id+"']";
    }

    //查找节点下元素, 并维护列表
    IMegaElement save;
    IMegaElement last;
    List<IMegaElement> tempChildren = app.findElements(by);
    do{
        children.addAll(tempChildren);
        save = tempChildren.get(tempChildren.size()-1);
        save.scrollTo();
        tempChildren = app.findElements(by);
        last = tempChildren.get(tempChildren.size()-1);
    }while(!last.equals(save));

    Iterator<IMegaElement> it = children.iterator();

    while(it.hasNext()){
        names.add(it.next().getAllText());
    }
    size = children.size();
}

IMegaElement 实现类 Element 部分代码

Element 对象表示的是 List 中的一个元素. hashCode() 方法中 index 为该元素在列表中的位置, 这个是在查找元素并创建对象的时候设置的.

 protected Element(WebElement webElement, IMegaApp app,By by) {
     this(webElement,app,by,-1);
 }

 protected Element(WebElement webElement, IMegaApp app, By by,int index){
     this.webElement = (MobileElement) webElement;
     id = ((MobileElement) webElement).getId();
     this.app = app;
     this.by = by;
     this.index = index;
     log = new Log(this.getClass().getSimpleName());
 }

@Override
 public boolean equals(Object object){
     if(!(object instanceof IMegaElement))
         return false;
     Element other = (Element) object;
     if(hashCode()!=other.hashCode())
         return false;
     return true;
 }

 @Override
 public int hashCode(){
     if(childrenText.isEmpty())
         getAllText();
     return (this.by.getType()+this.by.getParameter() + text + childrenText).hashCode();
 }

因为随着 ScrollView 的滚动, Android 中页面元素的 Id 会发生变化, 所以如何判断相对的对象比较麻烦, 我们使用的是元素本身及子节点的 text 相同及认为是同一个元素, 缺点就是如果一个容器中有 2 个对象的 text 完全一致就会有点问题, 不过貌似这也对用户也不友好. 以上内容仅是提供一个实现思路, 整体工程代码较多就不贴全了..

共收到 7 条回复 时间 点赞

楼主好想法!目前遇到在编写 Case 中最大的问题就是在需要使用 2 套不同的方式,如果封装后能加强 Case 的简洁,而把不同的实现放在后台自然是最好的了!

有时间的话楼主能介绍一下 你们是怎么实现 Android 和 IOS 同一套代码运行的么?

tbya #3 · 2015年06月29日 Author

@xdlhy 框架中开发的是常用移动端测试的接口, Android 和 ios 各有自己的实现类, 框架会自行识别当前的运行环境 (真机/模拟器, ios/android, 环境配置在 properties 文件中, 可遍历执行.) 来判断具体使用哪个实现类. 所以测试代码在不同平台上使用的是同一套接口也就不需要写 2 套代码了. 维护比较方便.

#3 楼 @tbya 意思理解了,非常感谢

IOS 下参杂 UIAScrollView 是无法使用 UIATableView 自动化遍历的 也就是 Selenium 的那套无效了 不知道是不是 bug

tbya #2 · 2015年07月08日 Author

@lanxiangtechnical 的确是的,需要自己来实现。

@tbya 有解决方案么 要不然 100 个子元素的话蛋碎了
我目前发现第一个子元素是可以打印出来并且成功操作的
但是接下去的循环就报错了
要是不掺杂 UIAScrollView 肯定没问题
我不知道要不要官方提 bug....

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