接触 Macaca 也蛮久了,中间断断续续折腾了一阵,自动化框架还在用老牌的 Appium,迁移是大事不能一蹴而就。最近有个机会准备分享一些 Macaca 的经验,我有开始来倒腾了。
使用 Macaca 做多终端的自动化对 Macaca 本身来说是支持的,可参考 xdf 分享的众多帖子,如:原来程序员都是这么聊天的,Macaca 如何实现多任务
接下来开始实验,PC 端多 electron 顺利完成。
接下来实验 Android,使用 TestNG 多线程方式运行 Suite 同时测试两个终端(代码在官方 macaca-test-sample-java 基础上修改)。
TestNG Suite
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="TestAndroid" parallel="tests" thread-count="2">
<test name="TestAndroid1">
<parameter name="port" value="4725" />
<parameter name="udid" value="192.168.239.101:5555" />
<classes>
<class name="macaca.client.AndroidSampleTestMulti" />
</classes>
</test>
<test name="TestAndroid2">
<parameter name="port" value="4726" />
<parameter name="udid" value="192.168.239.102:5555" />
<classes>
<class name="macaca.client.AndroidSampleTestMulti" />
</classes>
</test>
</suite>
Java Code
package macaca.client;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
import com.alibaba.fastjson.JSONObject;
import macaca.client.common.ElementSelector;
public class AndroidSampleTestMulti {
MacacaClient driver = new MacacaClient();
@Parameters({"port","udid"})
@BeforeClass
public void setUp(String port, String udid) throws Exception {
// platform: android or ios
String platform = "android";
JSONObject porps = new JSONObject();
porps.put("platformName", platform);
porps.put("app", System.getProperty("user.dir")+"/app/" + platform + "-app-bootstrap.zip");
porps.put("udid", udid);
porps.put("reuse", 1);
JSONObject desiredCapabilities = new JSONObject();
desiredCapabilities.put("host", "127.0.0.1"); // custom server host
desiredCapabilities.put("port", Integer.parseInt(port)); // custom server port
desiredCapabilities.put("desiredCapabilities", porps);
driver = driver.initDriver(desiredCapabilities);
}
@Test
public void test_case_1() throws Exception {
System.out.println("------------#1 login test-------------------");
driver.elementByXPath("//android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.RelativeLayout[1]/android.widget.EditText[1]").sendKeys("中文+Test+12345678");
ElementSelector selector = driver.elementsByClassName("android.widget.EditText");
selector.getIndex(1).sendKeys("111111");
driver.elementByName("Login").click().sleep(1000);
System.out.println("------------#2 scroll tableview test-------------------");
driver
.elementByName("HOME")
.click()
.elementByName("list")
.click()
.sleep(1000)
.swipe(200, 420, 200, 10, 50)
.sleep(5000);
System.out.println("------------#3 logout test-------------------");
driver
.back()
.elementByName("PERSONAL")
.click()
.sleep(1000)
.elementByName("Logout")
.click()
.sleep(1000);
}
@AfterClass
public void tearDown(MacacaClient driver) throws Exception {
driver.quit();
}
}
运行出现报错,错误信息如下:
macaca server --verbose
>> index.js:17:12 [master] pid:16776 webdriver server start with config:
{ port: 3456,
verbose: true,
always: true,
ip: '192.168.6.2',
host: 'DESKTOP-PHHDJ8D',
loaded_time: '2016-12-06 23:56:24' }
>> middlewares.js:17:10 [master] pid:16776 base middlewares attached
>> router.js:129:10 [master] pid:16776 router set
>> webdriver sdk launched
>> responseHandler.js:11:12 [master] pid:16776 Recieve HTTP Request from Client: method: POST url: /wd/hub/session, jsonBody: {"desiredCapabilities":{"app":"C:\\Users\\qianchang\\Desktop\\Macaca-Android\\macaca-test-sample-java-master/app/android-app-bootstrap.zip","reuse":1,"platformName":"android","udid":"192.168.239.101:5555"},"port":3456,"host":"127.0.0.1"}
>> session.js:47:10 [master] pid:16776 Creating session, sessionId: 0f5ef732-5336-4934-b8aa-f67cd243e2f3.
>> helper.js:196:12 [master] pid:16776 Unzipping local app form C:\Users\qianchang\Desktop\Macaca-Android\macaca-test-sample-java-master\app\android-app-bootstrap.zip
INSTRUMENTATION_STATUS: numtests=1
>> socket server ready
>> socket client ready
>> uiautomator-client.js:70:14 [master] pid:16776 connect lost
>> macaca-android.js:297:12 [master] pid:16776 UnknownError from uiautomator Error: This socket has been ended by the other party
>> responseHandler.js:54:12 [master] pid:16776 Send Error Respone to Client: UnknownError: An unknown server-side error occurred while processing the command.
>> responseHandler.js:60:14 [master] pid:16776 UnknownError: An unknown server-side error occurred while processing the command.
at Android.send (C:\Users\qianchang\AppData\Roaming\npm\node_modules\macaca-android\lib\macaca-android.js:298:11)
at throw (native)
at onRejected (C:\Users\qianchang\AppData\Roaming\npm\node_modules\macaca-cli\node_modules\.4.6.0@co\index.js:81:24)
>> responseHandler.js:76:14 [master] pid:16776 Send Bad HTTP Respone to Client: {"sessionId":"0f5ef732-5336-4934-b8aa-f67cd243e2f3","status":13,"value":{"message":"An unknown server-side error occurred while processing the command."}}
看到这个报错后跟 xdf 咨询问题原因,也跟 harsayer (小马) 讨论了一下,均有此现象,很着急啊有木有。还提了个issue到 github。
折腾了挺久没有找到解决方法,不断尝试,在晚上与君禾沟通过程中尝试在线程中加了一个等待。右键运行 TestNg Suite,神奇的事情发生了,两个服务端均正常初始化 driver,设备上正常执行测试脚本,是不是我的诚心感动了天地。
修改后的代码(只在初始化 driver 前加了一句等待,个人怀疑是不是由于底层 instrumentation 不支持同时访问导致,具体原因不明):
@Parameters({"port","udid"})
@BeforeClass
public void setUp(String port, String udid) throws Exception {
// platform: android or ios
String platform = "android";
JSONObject porps = new JSONObject();
porps.put("platformName", platform);
porps.put("app", System.getProperty("user.dir")+"/app/" + platform + "-app-bootstrap.zip");
porps.put("udid", udid);
porps.put("reuse", 1);
JSONObject desiredCapabilities = new JSONObject();
desiredCapabilities.put("host", "127.0.0.1"); // custom server host
desiredCapabilities.put("port", Integer.parseInt(port)); // custom server port
desiredCapabilities.put("desiredCapabilities", porps);
if(port.equals("4726"))
{
Thread.sleep(1000);
}
driver = driver.initDriver(desiredCapabilities);
System.out.println(driver);
}
运行效果: