Appium [已解决] 一台电脑开启两个 Appium 客户端,分别控制两台测试设备进行联动测试

剪烛 · July 02, 2015 · Last by 丫丫 replied at March 27, 2017 · 3068 hits

需求

对两台测试设备进行测试,一台测试设备为 Android 设备,一台为 iOS 设备,类似用 iPhone 充当遥控器控制一台 Android 盒子。
因为手上暂时并没有 mac 环境,暂时用两台 Android 设备测试。

操作

电脑开启两个 Appium 客户端,将其中一个客户端的端口改为:4725
运行后,验证了两个地址都正常返回: http://127.0.0.1:4723/http://127.0.0.1:4725/

client 端代码

DesiredCapabilities capabilities = new DesiredCapabilities(); 
capabilities.setCapability("device","Android");
capabilities.setCapability("deviceName", "b1d12c6");
capabilities.setCapability("platformVersion", "4.4.4");  
capabilities.setCapability("platformName", "Android");
capabilities.setCapability("appPackage", "com.my.pkg");  
capabilities.setCapability("appActivity", "com.my.pkg.LoadingActivity");
driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);

DesiredCapabilities capabilities2 = new DesiredCapabilities(); 
capabilities2.setCapability("device","Android");
capabilities2.setCapability("deviceName", "0123456789ABCDEF");
capabilities2.setCapability("platformVersion", "4.4.4");  
capabilities2.setCapability("platformName", "Android");
capabilities2.setCapability("appPackage", "com.my.pkg");  
capabilities2.setCapability("appActivity", "com.my.pkg.LoadingActivity");
driver2 = new AndroidDriver(new URL("http://127.0.0.1:4725/wd/hub"), capabilities2);

执行结果

client 端:
deviceName=b1d12c6 找不到 Session

org.openqa.selenium.remote.SessionNotFoundException: 
Command duration or timeout: 5 milliseconds
Build info: version: '2.45.0', revision: '5017cb8', time: '2015-02-26 23:59:50'
System info: host: 'RMTCNW20054', ip: '192.168.21.48', os.name: 'Windows 7', os.arch: 'amd64', os.version: '6.1', java.version: '1.7.0_67'
Session ID: edc5d7c6-892f-401d-8f26-049d0ffab5eb
Driver info: io.appium.java_client.android.AndroidDriver
Capabilities [{platform=LINUX, javascriptEnabled=true, appActivity=com.runmit.sweedee.LoadingActivity, browserName=Android, networkConnectionEnabled=true, desired={platformVersion=4.4.4, platformName=Android, deviceName=b1d12c6, appActivity=com.runmit.sweedee.LoadingActivity, device=Android, appPackage=com.runmit.sweedee}, locationContextEnabled=false, appPackage=com.runmit.sweedee, platformVersion=4.4.4, databaseEnabled=false, platformName=Android, deviceName=0123456789ABCDEF, webStorageEnabled=false, device=Android, warnings={}, takesScreenshot=true}]
    ......

测试设备:
被测程序在一台机器(deviceName=0123456789ABCDEF)启动了两次,而另外一台机器没有任何执行。
Appium 日志:
4723 端口的 Appium 服务端的日志中,deviceName 从 b1d12c6 变成了 0123456789ABCDEF

info: --> POST /wd/hub/session {"desiredCapabilities":{"platformVersion":"4.4.4","deviceName":"b1d12c6","platformName":"Android","appActivity":"com.runmit.sweedee.LoadingActivity","device":"Android","appPackage":"com.runmit.sweedee"}}
info: Client User-Agent string: Apache-HttpClient/4.3.6 (java 1.5)
info: [debug] The following desired capabilities were provided, but not recognized by appium. They will be passed on to any other services running on this server. : device
info: [debug] Didn't get app but did get Android package, will attempt to launch it on the device
info: [debug] Creating new appium session 05488004-2912-4243-ad70-690ebaf420e3
info: Starting android appium
info: [debug] Getting Java version
info: Java version is: 1.7.0_67
info: [debug] Checking whether adb is present
info: [debug] Using adb from D:\software\adt-bundle-windows-x86_64-20140702\sdk\platform-tools\adb.exe
warn: No app capability, can't parse package/activity
info: [debug] Set chromedriver binary as: C:\Program Files (x86)\Appium\node_modules\appium\build\chromedriver\windows\chromedriver.exe
info: [debug] Using fast reset? true
info: [debug] Preparing device for session
info: [debug] Not checking whether app is present since we are assuming it's already on the device
info: Retrieving device
info: [debug] Trying to find a connected android device
info: [debug] Getting connected devices...
info: [debug] executing cmd: D:\software\adt-bundle-windows-x86_64-20140702\sdk\platform-tools\adb.exe devices
info: [debug] 2 device(s) connected
info: Found device 0123456789ABCDEF
info: [debug] Setting device id to 0123456789ABCDEF
.......之后所有的日志中的 deviceName 全部为 0123456789ABCDEF

从现象上看,好像是 client 发送的 json 信息中 deviceName 确实是 b1d12c6,但是 Appium 在执行时,将 deviceid 设置成了另一台的测试设备的 deviceName 0123456789ABCDEF
导致设备 0123456789ABCDEF 上运行了两次脚本

这是为什么?

是 Appium 本身不支持电脑运行多个服务端?还是我 client 的 bug?

两台电脑分别运行 Appium 服务端

两台电脑分别运行 Appium 服务端,端口的 ip 改为电脑真实的 ip,然后通过脚本操作两个 Appium 服务端分别控制两个测试设备,这样是 OK 的。但是平白多浪费一台电脑,感觉实在有点浪费。

解决方法

设置 udid

DesiredCapabilities capabilities = new DesiredCapabilities(); 
capabilities.setCapability("device","Android");
capabilities.setCapability("deviceName", "b1d12c6");
capabilities.setCapability("udid", "b1d12c6");
capabilities.setCapability("platformVersion", "4.4.4");  
capabilities.setCapability("platformName", "Android");
capabilities.setCapability("appPackage", "com.runmit.sweedee");  
capabilities.setCapability("appActivity", "com.runmit.sweedee.LoadingActivity");
driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);

DesiredCapabilities capabilities2 = new DesiredCapabilities(); 
capabilities2.setCapability("device","Android");
capabilities2.setCapability("deviceName", "0123456789ABCDEF");
capabilities2.setCapability("udid", "0123456789ABCDEF");
capabilities2.setCapability("platformVersion", "4.4.4");  
capabilities2.setCapability("platformName", "Android");
capabilities2.setCapability("appPackage", "com.runmit.sweedee");  
capabilities2.setCapability("appActivity", "com.runmit.sweedee.LoadingActivity");
driver2 = new AndroidDriver(new URL("http://127.0.0.1:4725/wd/hub"), capabilities2);

之后同时启动成功

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

adb 每次默认的是第一个识别到的 devices,

剪烛 #2 · July 02, 2015 Author

#1 楼 @testly 那写 devicename 感觉没什么意义啊~~(╯﹏╰) b
那么用一个 ios 设备感觉会没问题?

#2 楼 @shixue33 ios 的话 Xcode 本身就只能调试一个设备,

剪烛 #4 · July 02, 2015 Author

#3 楼 @testly 嗯嗯,我意思是如果是 mac 上接一台安卓设备,一台 iOS 设备的话

#2 楼 @shixue33 有个想法,可以利用 docker 开 N 个 container ,每个 container connect 一个 IP 端口 adb 通过 WiFi 映射 脱离数据线 无线控制多台手机!

剪烛 #6 · July 02, 2015 Author

#5 楼 @testly ! 可以尝试下 (・ิϖ・ิ) っ

可以这么做:
1、Appium Server启动的时候分别指定好 UDID、Port(主要是 AppiumPort、bootStrapPort)
2、脚本里 session 别起两个了,用例这样参在一起容易出问题的,用例就按照 suite 或者类区分开来
3、同时执行两个 testSuite,就不冲突了

appium/lib/devices/android/android-common.js

if (this.adb.udid) {
      if (!_.contains(_.pluck(devices, 'udid'), this.adb.udid)) {
        return cb(new Error("Device " + this.adb.udid + " was not in the list " +
                            "of connected devices"));
      }
      deviceId = this.adb.udid;
    }

android 上 deviceName 确实没啥用,要指定设备需要用 udid 。

这个文档也有说明:
https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/caps.md

剪烛 #9 · July 03, 2015 Author

#8 楼 @chenhengjie123 #7 楼 @anikikun #5 楼 @testly
3q ~已经解决~
capabilities 中设置 udid 后,可以同时启动两台测试设备

剪烛 #10 · July 03, 2015 Author

#7 楼 @anikikun 我估计分开写不太好写。我先尝试下。

capabilities 中配置 udid 或者 appium 启动的时候,带-U udid -port 端口,两种方式能解决一台 PC 控制多台终端问题;从 Appium 服务代码来看,Appium 是根据用户是否在 capabilities 配置了 udid,如果配置了,则直接 pick 这台 device,如果没有配置,则 pick 第一台设备,片源如下:

官网针对多机执行解释如下:

#9 楼 @shixue33 很赞啊~联动测试的解决方案那么就有了。
这样一来,两个用户互相收发消息的用例都可以很还原得做了。

两个设备交互写到两个 suit 挺麻烦的,交互能分开测吗,变成
iPhone --> fake server
fake client --> 盒子

很好呀~~~

剪烛 #15 · July 03, 2015 Author

#13 楼 @sanlengjingvv 我觉得让我自己去拼装 json 数据,真的还挺麻烦的。json 数据复杂,
如果有工具能将 http 请求录制下来,可能会好点

不需要拼装 json

剪烛 #17 · July 03, 2015 Author

#16 楼 @a00ium 那怎么操作呢?

看了那么多帖子了 看来做出来的人是不愿意分享出来的 还有人说已经跑了半年了。。+@shixue33

剪烛 #19 · July 03, 2015 Author

#18 楼 @a00ium ⊙﹏⊙!!!

pls check email @shixue33

#9 楼 @shixue33 怎么解决的呢,刚接触呢,求指教,也想同时启动两台测试设备

@shixue33 同求解决方案,没有思路

@shixue33 楼主,这个问题怎么解决的,告诉下思路

用 appium 在同一台电脑上启动了两个 server,分别用两台实体机去链接不同的 server,发现拿到的 sessionId 却是一致的,这个怎么处理?

#24 楼 @ji_an_ke 你把日志贴出来看一下

#22 楼 @xuanjian 分别设置 udid 就好了

求问,我根据你的代码写的然后还是出问题了,就运行到这里一只下不去

#27 楼 @litost 官方群找下我(剪烛),你提供的信息不全,我帮你排查下

官方群没理我没理我,加不进来,我的 qq1369449700

#25 楼 @shixue33 最终解决了,自己太粗心

剪烛 [Topic was deleted] 中提及了此贴 14 Nov 21:58

我想问下,这边的 udid 是 adb devices 命令查看到的第一列的那一串数字吗?之前写了程序获取 udid=7d93c668-d2d2-32eb-826f-e3eadeeedb36,结果 appium 报找不到设备

剪烛 #34 · December 20, 2016 Author

#33 楼 @mona0505 不太像 Android 的啊……Android 的一般没这么长,你这是 iOS 的设备么?

adb devices
List of devices attached
c146cbc5    device

#34 楼 @shixue33 所以这边指定的 udid 就是通过 adb devices 看到的第一列的那一串咯?咦~~~

#34 楼 @shixue33 不是 IMEI 或者 IMSI 之类的?

#37 楼 @shixue33 好的,谢谢!

太好了,解决了我的问题,nice

按照这个方法,确实能启动两台机器了,但是却只在一台机器上执行了用例,这是为什么呢?

剪烛 #41 · March 13, 2017 Author
zenghuan 回复

介不介意把代码贴上来看下呢?

Mr_C 回复

想请问下,你这个情况最后怎么解决的?目前我也遇到这个问题了

剪烛 #43 · March 27, 2017 Author
丫丫 回复

你好,分别指定 udid 就可以解决,如果需要完全并行,在脚本使用两个线程就可以了

剪烛 回复

真的吗!

剪烛 #45 · March 27, 2017 Author
回复

吓得我马上去试一下

剪烛 回复

在脚本使用两个线程是什么意思?

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