在 TesterHome 挺久了,一般是看帖比较少发,
最近有看到一些同学做多设备的 Appium 测试有碰到一些问题。
刚好自己前段也涉及到类似的方案,在这里分享些自己这段碰到的一些问题阻碍,和解决的一些思路吧,刚涉及 UI 自动化不久,很多东西还很生疏,欢迎大家提点。
1.需求和条件制约
最早需求的提出,场景的要求是要同时实现几十台设备的 UI 自动化测试且是有客户端的交互行为,部分设备运行的 APP 需要等待其他设备的 APP 进行操作。
APP 是 Hybrid 类型的,内嵌了 webview,且该 webview 是自定义过的,robutim 是无法识别到控件,尝试过录制器也无法用,而尝试了 appium 则是可以使用的因为是 chromedriver 控制的。
设备数量大概是在 60 左右,要求持续运行较久的时间,那么设备需要持续 USB 供电,就不能直接连 PC 跑脚本 (PS:PC 也没那么多口接这么多设备)
那么需求就清晰了:用 appium 在同个用例里进行 60 台设备的 UI 自动化控制。
2.方案实施
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 来处理的,这里也不细写了,运行的部分日志结果如下: