Appium 使用 Appium 进行多设备的集群分布式 UI 自动化测试

汪汪 · 2015年07月08日 · 最后由 ningquanshui 回复于 2015年07月15日 · 7365 次阅读
本帖已被设为精华帖!

在 TesterHome 挺久了,一般是看帖比较少发,
最近有看到一些同学做多设备的 Appium 测试有碰到一些问题。
刚好自己前段也涉及到类似的方案,在这里分享些自己这段碰到的一些问题阻碍,和解决的一些思路吧,刚涉及 UI 自动化不久,很多东西还很生疏,欢迎大家提点。

1.需求和条件制约
最早需求的提出,场景的要求是要同时实现几十台设备的 UI 自动化测试且是有客户端的交互行为,部分设备运行的 APP 需要等待其他设备的 APP 进行操作。
APP 是 Hybrid 类型的,内嵌了 webview,且该 webview 是自定义过的,robutim 是无法识别到控件,尝试过录制器也无法用,而尝试了 appium 则是可以使用的因为是 chromedriver 控制的。
设备数量大概是在 60 左右,要求持续运行较久的时间,那么设备需要持续 USB 供电,就不能直接连 PC 跑脚本 (PS:PC 也没那么多口接这么多设备)
那么需求就清晰了:用 appium 在同个用例里进行 60 台设备的 UI 自动化控制。

2.方案实施

  1. 首先因为无法 USB 连接,这里全部都使用无线 ADB 连接,之前有同学写过使用无线 adb 工具进行连接的文章,其实只要有 root 权限,一个命令就可以搞定了。 在 cmd 运行 adb tcpip 5555,可以启动 5555 端口的监听,如果需要切换回 usb 则运行 adb usb 打开tcpip监听 之后通过 adb connect IP 进行设备的无线调试连接,adb disconnect IP 来断开连接 这里写图片描述

2.然后开始多设备时的 Appium Server 控制,因为 Appium Server 与设备要一一对应,所以需要启动较多的 server,所以肯定不选择 windows 版本的 server 控制,因为启动需要手动去点击,出现问题也无法重新启动。
那么就使用命令行模式的 (PS:部分同学因为被墙的原因无法 npm 进行安装,这里有个小技巧,可以帮助你们装完 windows 版的 appium server 后依然可以使用命令行的:传送门)

设计 AppiumServer 类来进行 Server 的批量启动控制如下。

public class AppiumServer {
    LogUtil log = new LogUtil();

    public AppiumServer(){      
        KillTask("node.exe");
        log.info("init appium server...");
    }

    public void KillTask(String taskname){
        String Command = "taskkill /F /im " + taskname;
        log.info("kill " + taskname + " task ...");
        runCommand(Command);
    }

    public void runServer(int port,String udid) {
        log.info("run " + udid + " Appium Server in port " + port + "...");
        int bpport = port +1;
        int chromeport = port + 4792;
        //多设备server端需要手动指定每台设备的udid,安卓无线连接下就是设备的ip:port..
        String Command = "appium.cmd -p " + port + " -bp " + bpport + " --session-override --chromedriver-port "+ chromeport +" -U " 
                         + udid +  " >c://" + port + ".txt";
        log.info(Command);
        runCommand(Command);
    }

    private void runCommand(String command){
        try {
            Runtime.getRuntime().exec(command);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

启动 server

AppiumServer AS = new AppiumServer();
AS.runServer(4723, "192.168.1.17:5555");

3.对于同时启动大量的 AppiumServer 运行 webview 的测试,在实际运行时,出现问题了,当启动的设备超过十几台时候,adb 的进程数会达到几十个,数量达到一定程度后,adb 会停止响应并结束进程断开所有设备,而且 webview 进行测试的时候会需要启动 chromedriver 进程,与设备也是一一对应,启动超过十几个进程并行执行,也会出现很多不稳定的不识别或者停止响应的情况。
针对这个问题,其实原因还是 windows 下的 adb 太脆弱了,结合 Appium 的 Server 支持远程执行的情况,搭建多台 Linux 环境的 PC 来做 Appium Server 端的运行执行 (最后实际测试 linux 下同时可以承载 30+ 台设备妥妥的),Server 的启动控制使用 STAF 进行控制。(PS:STAF 环境搭建之后再整理份,不过百度下应该挺多)
搭建好 STAF 环境后,导入 JSTAF.jar 并增加 staf 的运行控制方法如下

import com.ibm.staf.STAFException;
import com.ibm.staf.STAFHandle;

    ......
    private void runRemoteCommand(String command){
         try {
             handle = new STAFHandle("MySTAF");
         } catch (STAFException e) {
             System.out.println("Error registering with STAF, RC: " + e.rc);
         }
         String service = "PROCESS";
         String request = "start command shell \"" + command + "\"";
         try {
            handle.submit2(ServerIP, service, request);
            handle.unRegister();
         } catch (STAFException e) {
             System.out.println("run process error");
         }       
    }

修改 LinuxServer 的启动方法如下:

private String LinuxAppiumPath = "/usr/local/lib/node_modules/appium/bin";
public AppiumServer(String ServerType, String ip){
        this.setServerType(ServerType);
        this.setServerIP(ip);
        this.isRemote = true;
        KillTask("node");
        log.info("init remote appium server at "+ ip +"...");
    }
......
public void runLinuxServer(int port,String udid) {
        log.info("run " + udid + " Appium Server in port " + port + "...");
        int bpport = port +1;
        int chromeport = port + 4792;
        String Command = "/usr/bin/node " + LinuxAppiumPath +"/appium.js -a " + ServerIP +" -p " + port + " -bp " + bpport + " --session-override --chromedriver-port "+ chromeport +" -U " + udid +  " >/home/wang/log/" + port + ".log";
        log.info(Command);
        runRemoteCommand(Command);      
    }

(当然 AppiumServer 类还需要进行一些对应的逻辑调整,比如区分开远程和本地的 Server 执行的方法,区分 Server 的 Type,区分 IP 等。这里就不细说了)
3.流程图
大致画了个简单原理的流程图如下:
这里写图片描述

4.运行结果
具体的用例构建和脚本是用 testNG 加 testReport 来处理的,这里也不细写了,运行的部分日志结果如下:
这里写图片描述

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 29 条回复 时间 点赞

好高端,可以试试 下,也许以后会用到

卧槽。。。这是逼我吐槽啊。。testerhome,不是 testhome!!!!

好文是好文 就是 testerhome 不是 testhome。。。

#3 楼 @lihuazhang 好伤心。。。

分享的不错!
我这边有两个问题,
第一:执行这个方案的前提是 60 多台设备都要越狱?
第二:你这种方案 无论是用 adbWireless 或者其他的 adb connect 这种 ,对 wifi 的依赖性太强,很有可能网络不稳定,导致其中几台失败!!
最后一个问题:我好伤心,是 testerhome 不是 testhome

其实 PC 可以分解多很多个 usb 口!!根据性能配置来区分的话,中高端 PC 可以分解 100 个以上的 usb 端口

汪汪 #25 · 2015年07月08日 Author

#4 楼 @monkey 哈哈。。居然打错了 马上改。。。。

汪汪 #24 · 2015年07月08日 Author

#5 楼 @testly 额 这个暂时我只在安卓上用 所以不存在越狱的问题。。。 二的话 因为方案是在内部局域网运行的 独立的自组网,所以 wifi 速度不是问题,当然 问题还是有的。。。还需要不断完善

#7 楼 @wang04170 Hydird 也拼写错了。。再次伤心了。。。

汪汪 #10 · 2015年07月08日 Author

#9 楼 @monkey T_T 多谢指正。。哈哈哈 英文太渣。。。。 见笑见笑~~

#10 楼 @wang04170 其实还是改错了。。我帮你改过来了。。= =

#8 楼 @wang04170 说错了。是 root

60 台 root 的设备!!!

#13 楼 @anikikun 怎么那么叼呢。。。

所以那些手机云测试平台的搭建也是这种思路吗?

16楼 已删除

@apert 我打赌云测试平台不是这样子的 稳定性可想而知
他们一般都是做硬件层的控制

汪汪 #19 · 2015年07月09日 Author

#17 楼 @lanxiangtechnical 嗯 无线太不稳了。。。云测不会是这样做的 。。。

旺仔 V5

#19 楼 @wang04170 60 个设备你不会一个一个 adb connect ip 吧?

汪汪 #10 · 2015年07月10日 Author

#21 楼 @yuwuhen333 windows 下用 C# 写了个窗体工具,可以批量管理的,linux 下的话 用 sh 脚本管理

网龙 c# 算是用得最好的了哈 91 助手不错 赞个 (c++ 重构的不算)
这个批量管理的分享下呗@wang04170

换言之,这个不适用未 root 的手机吧?正苦恼 QA manager 要求我们必须用未 root 得手机来测试,请问有好的解决方案吗?

有两个问题想请教下:
一.使用 STAF 的确解决了远程服务器下发命令的问题,但是我们做远程设备部署是为了想让设备更好的利用,也就是说远程服务器可能会有几百台手机,不同产品跑只会在这之中选择空闲的设备来跑,这里需要实现自动监控各结点运行状态,并行的分发任务到各结点上。原来的方案是使用 selenium grid,其中有几个问题没解决:1.远程服务器 adb 命令执行,或许可以使用 STAF 来解决。2.selenium grid 可以自动分发 node,但是暂时我们没有找到方法查询各 node 结点的状态,我们想做一个设备使用状态可视化的看板?不知道谁实现了。
二、设备和 node 结点通过无线连接,但是各设备其实是与相应的 node 结点的具体的端口一一对应的吧?

汪汪 #26 · 2015年07月12日 Author

#23 楼 @doria 只是针对性的做个小工具而已,方便操作用,BUG 还很多的,在其他项目的实用性不大,还是不献丑了哈

#25 楼 @springs412 我使用的场景暂时没你们的那么大哈,所以节点监控什么的,都是没考虑的,以后有机会再慢慢做完善哈。。第二个问题是的 无线只是用来 ADB 连接到设备上用,实际上设备的通讯还是通过具体的端口,只不过途径走的是无线连接。其实就类似手机用 WIFI 访问 IIS 服务器一样

在使用 JSTAF 时遇到下面问题,能否帮忙解决下:
D:\java\jdk1.7.0_45\bin\JSTAF.dll: Can't find dependent libraries

汪汪 #29 · 2015年07月15日 Author

#28 楼 @springs412 试下装下 STAX 再配置下 cfg

我是在 windows 环境下配置的,按http://blog.csdn.net/apple__tree/article/details/6027084这个贴子配的,好像都正常启动了。
但是用代码调用就是报错 D:\java\jdk1.7.0_45\bin\JSTAF.dll: Can't find dependent libraries
能不能留个联系方式给我,或者加下我的 QQ:40840171
帮我解决下这个问题。

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