接触 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);
    }

运行效果:


↙↙↙阅读原文可查看相关链接,并与作者交流