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

汪汪 · July 08, 2015 · Last by ningquanshui replied at July 15, 2015 · 6610 hits
本帖已被设为精华帖!

在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端口

汪汪 #7 · July 08, 2015 作者

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

汪汪 #8 · July 08, 2015 作者

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

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

汪汪 #10 · July 08, 2015 作者

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

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

#8楼 @wang04170 说错了。是root

60台root的设备!!!

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

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

16Floor has been deleted

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

汪汪 #19 · July 09, 2015 作者

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

旺仔V5

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

汪汪 #22 · July 10, 2015 作者

#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 · July 12, 2015 作者

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

汪汪 #27 · July 12, 2015 作者

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

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

汪汪 #29 · July 15, 2015 作者

#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
帮我解决下这个问题。

31Floor has been deleted
需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up