Macaca 使用 Macaca 进行 Android 多设备测试

adfghzhang · 2016年12月08日 · 最后由 回复于 2018年03月27日 · 2014 次阅读

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

运行效果:

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

就等待一下? 。。。 介个 还是底层 macaca server 或底层组件驱动层 解决掉比较好。。。否则不能叫支持多设备并发

初始化之前怎么保证 server 端开启了?

#2 楼 @xdf 是的哦,昨晚跟君禾还发了截图的

初始化只是创建了 session

5楼 已删除

小小等待 居然可以了

请问只能测浏览器页面吗?native 能不能测?

#8 楼 @simple 我的例子就是 native 的,harsayer 发的是 H5 的,Hybrid 也一样能测。

如何处理不同设备上必须用不同账号使用的问题呢?根据 uid 指定账号吗


多开了一个 macaca server 会提示端口改变,怎么实现开启多个 macaca 服务

#11 楼 @leyili1988 你的 3456 端口被占用了,自动改到 21698 端口了

@adfghzhang 恩恩 谢谢 明白了 我想用五六十部安卓机子同时操作,就得开五六十个服务哦

@adfghzhang 解决了 我把时间延迟两秒,请问一下如果设备越多是不是延迟的时间就要更长

#15 楼 @leyili1988 这个我不是很清楚,加延时是一定能跳过这个问题,具体加多少我只能说需要你尝试

@adfghzhang 看了你的帖子,我用真机测试时,日志都打印到 macaca server --verbose 的窗口,没的打印到 macaca server -p 4725 --verbose macaca server -p 4726 --verbose2 个窗口,请教一下,这个需要在案例脚本中有什么设置吗?


请问这是为啥

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册