Appium Appium 运行 python 脚本速度很慢

fanfaneve · 2015年04月22日 · 最后由 fanfaneve 回复于 2015年04月24日 · 2765 次阅读

Appium 菜鸟一只,求问在 IOS 环境下运行 python 脚本,无论是在模拟器上还是真机上,都感觉速度很慢,比手动操作还要慢好多,简直不能忍。Mac,Xcode,Appium 的版本都是最新的。有什么设置可以加快运行速度吗?请大神指教。
之前用 Mac 自带的 UIAutomator 生成 JavaScript, 跑起来速度很快的。

Python 脚本如下:

import os
from random import randint
from appium import webdriver
from time import sleep

success = True
desired_caps = {}
desired_caps['appium-version'] = '1.0'
desired_caps['platformName'] = 'iOS'
desired_caps['platformVersion'] = '8.1'
desired_caps['deviceName'] = 'iPhone 5'
desired_caps['app'] = os.path.abspath('/Users/pod/Downloads/appium_test_sample/sample-code-master/sample-code/apps/TestApp/build/Release-iphonesimulator/TestApp.app')

wd = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
wd.implicitly_wait(60)

def is_alert_present(wd):
    try:
        wd.switch_to_alert().text
        return True
    except:
        return False

try:
    wd.get_screenshot_as_file("/Users/pod/Downloads/appium_test_sample/sample-code-master/sample-code/apps/TestApp/screenshot/begin1.png")
    wd.find_element_by_name("IntegerA").click()
    wd.find_element_by_name("more, numbers").click()
    wd.find_element_by_name("1").click()
    wd.find_element_by_name("2").click()
    wd.find_element_by_name("3").click()
    wd.find_element_by_name("4").click()
    wd.find_element_by_name("IntegerB").click()
    wd.find_element_by_name("more, numbers").click()
    wd.find_element_by_name("8").click()
    wd.find_element_by_name("9").click()
    wd.find_element_by_name("1").click()
    wd.find_element_by_name("5").click()
    wd.find_element_by_name("ComputeSumButton").click()
    wd.find_element_by_name("show alert").click()
    wd.find_element_by_xpath("//UIAApplication[1]/UIAWindow[4]/UIAAlert[1]/UIACollectionView[1]/UIACollectionCell[2]/UIAButton[1]").click()
    wd.find_element_by_name("Done").click()
    wd.find_element_by_name("Test Gesture").click()
    wd.get_screenshot_as_file("/Users/pod/Downloads/appium_test_sample/sample-code-master/sample-code/apps/TestApp/screenshot/end1.png")
finally:
    wd.quit()
    if not success:
        raise Exception("Test failed.")
共收到 16 条回复 时间 点赞

先确定慢在什么地方吧. 然后再决定如何优化. appium 整体的确是慢的.

启动的时候慢也就算了,但是运行起来每按一个键都要等 1-2s 再按第二个键,跑完一个简单的脚本都要跑好久,这是正常的吗?

#2 楼 @fanfaneve
大哥 启动能不慢吗?

Android.prototype.start = function (cb, onDie) {
  this.launchCb = cb;
  this.uiautomatorExitCb = onDie;
  logger.info("Starting android appium");
  async.series([
    this.initJavaVersion.bind(this),
    this.initAdb.bind(this),
    this.initUiautomator.bind(this),
    this.prepareDevice.bind(this),
    this.packageAndLaunchActivityFromManifest.bind(this),
    this.checkApiLevel.bind(this),
    this.pushStrings.bind(this),
    this.processFromManifest.bind(this),
    this.uninstallApp.bind(this),
    this.installAppForTest.bind(this),
    this.forwardPort.bind(this),
    this.pushAppium.bind(this),
    this.initUnicode.bind(this),
    this.pushSettingsApp.bind(this),
    this.pushUnlock.bind(this),
    function (cb) {this.uiautomator.start(cb);}.bind(this),
    this.wakeUp.bind(this),
    this.unlock.bind(this),
    this.getDataDir.bind(this),
    this.setupCompressedLayoutHierarchy.bind(this),
    this.startAppUnderTest.bind(this),
    this.initAutoWebview.bind(this)
  ], function (err) {
    if (err) {
      this.shutdown(function () {
        this.launchCb(err);
      }.bind(this));
    } else {
      this.didLaunch = true;
      this.launchCb(null, this.proxySessionId);
    }
  }.bind(this));
};

this.installAppForTest.bind(this),
this.pushUnlock.bind(this),
等动作都比较耗时。
有些没必要的你完全可以注释掉。

我现在是自己将 server 端的代码修改了一部分,速度要好很多.

“Mac 自带的 UIAutomator 生成 JavaScript, 跑起来速度很快的。”

对于你说的很快,夸张了吧,Appium 比起直接用 Uiautomator(Android)写的 jar,执行起来是要慢点,但是也不至于你说的那么慢吧 .

Appium 真正驱动手机执行的动作的部分,还是依赖的是设备平台自己的测试框架,例如 Andorid 下面的 Uiautomator,具体实现你去看 Bootstrap 的源码:

static {
    map.put("waitForIdle", new WaitForIdle());
    map.put("clear", new Clear());
    map.put("orientation", new Orientation());
    map.put("swipe", new Swipe());
    map.put("flick", new Flick());
    map.put("drag", new Drag());
    map.put("pinch", new Pinch());
    map.put("click", new Click());
    map.put("touchLongClick", new TouchLongClick());
    map.put("touchDown", new TouchDown());
    map.put("touchUp", new TouchUp());
    map.put("touchMove", new TouchMove());
    map.put("getText", new GetText());
    map.put("setText", new SetText());
    map.put("getName", new GetName());
    map.put("getAttribute", new GetAttribute());
    map.put("getDeviceSize", new GetDeviceSize());
    map.put("scrollTo", new ScrollTo());
    map.put("find", new Find());
    map.put("getLocation", new GetLocation());
    map.put("getSize", new GetSize());
    map.put("wake", new Wake());
    map.put("pressBack", new PressBack());
    map.put("pressKeyCode", new PressKeyCode());
    map.put("longPressKeyCode", new LongPressKeyCode());
    map.put("takeScreenshot", new TakeScreenshot());
    map.put("updateStrings", new UpdateStrings());
    map.put("getDataDir", new GetDataDir());
    map.put("performMultiPointerGesture", new MultiPointerGesture());
    map.put("openNotification", new OpenNotification());
    map.put("source", new Source());
    map.put("compressedLayoutHierarchy", new CompressedLayoutHierarchy());
  }

这个 map 里面 key 所对应的方法里面的动作,其实基本上都是 Uiautomator 的接口去实现的。
所以慢也不至于像你说的那么慢。
httpserver 和 scriptClient,BootStrap 和 AppiumServer 之间的通行的确会消耗掉一部分时间。

是慢的了...各种 server..

calabash 快...robotium 快..
.

#5 楼 @anikikun

启动慢是一回事,脚本没单个动作慢是另一回事。

脚本单个动作慢 可能需要看看具体实现

def _get_opts(self, element, x, y, duration = None):
        opts = {}
        if element is not None:
            opts['element'] = element.id

        # it makes no sense to have x but no y, or vice versa.
        if x is None or y is None:
            x, y = None, None
        opts['x'] = x
        opts['y'] = y

        if duration is not None:
            opts['duration'] = duration

        return opts

得看看默认 duration 是不是为 None,有些默认 duration 可能设置有基础时间

#2 楼 @fanfaneve 能给个时间对比吗?
例如用 UIAutomation 执行你上面脚本这么多操作需要多少时间(s),用 Appium 执行同样操作是多少时间(s)。既然想优化,那就要先有指标作参考。
或者你可以打开 appium server 的 --log-timestamp 选项,在 log 里面增加时间戳,然后把 log 贴出来看看到底时间都去哪里了。

Appium 相比 UIAutomation 会慢的可能原因有:

  1. Appium 还要帮你装应用(UIAutomation 的运行前提就是应用已经启动,所以这个时间在 UIAutomation 上其实是被忽略了)
  2. Appium 是通过 instrument 与 UIAutomation 通讯来进行操作的,启动 instrument 的时间、通讯时间以及 appium 解析各种请求的时间也是比 UIAutomation 慢的原因(因为都是相比 UIAutomation 增加的操作)。

#7 楼 @chenhengjie123
我用了--log-timestamp,这是点击一个按键的 log,后发现
2015-04-24 02:49:53:329 - info: [debug] [INST] 2015-04-24 02:49:54 +0000 Debug: Got new command 3 from instruments: au.getElementByName('IntegerA')
以及
2015-04-24 02:49:54:433 - info: [debug] [INST] 2015-04-24 02:49:55 +0000 Debug: Got new command 4 from instruments: au.tapById('0')
都和上面相差了 1s,请问这是什么原因?

2015-04-24 02:49:52:349 - info: --> POST /wd/hub/session/ad96edc6-92b4-4b29-a2fc-d98281c83664/element {"using":"name","sessionId":"ad96edc6-92b4-4b29-a2fc-d98281c83664","value":"IntegerA"}
2015-04-24 02:49:52:349 - info: [debug] Waiting up to 0ms for condition
2015-04-24 02:49:52:349 - info: [debug] Pushing command to appium work queue: "au.getElementByName('IntegerA')"
2015-04-24 02:49:52:350 - info: [debug] Sending command to instruments: au.getElementByName('IntegerA')
2015-04-24 02:49:53:329 - info: [debug] [INST] 2015-04-24 02:49:54 +0000 Debug: Got new command 3 from instruments: au.getElementByName('IntegerA')
2015-04-24 02:49:53:331 - info: [debug] [INST] 2015-04-24 02:49:54 +0000 Debug: evaluating au.getElementByName('IntegerA')
2015-04-24 02:49:53:332 - info: [debug] [INST] 2015-04-24 02:49:54 +0000 Debug: evaluation finished
2015-04-24 02:49:53:334 - info: [debug] [INST] 2015-04-24 02:49:54 +0000 Debug: Lookup returned [object UIATextField] with the name "IntegerA" (id: 0).
2015-04-24 02:49:53:335 - info: [debug] [INST] 2015-04-24 02:49:54 +0000 Debug: responding with:
2015-04-24 02:49:53:337 - info: [debug] [INST] 2015-04-24 02:49:54 +0000 Debug: Running system command #4: /usr/local/bin/node /usr/local/lib/node_modules/appium/node_modules/appium-uiauto/bin/command-proxy-client.js /tmp/instruments_sock 2,{"status":0,"value":{"ELEMENT":"0"}}...
2015-04-24 02:49:53:443 - info: [debug] Socket data received (38 bytes)
2015-04-24 02:49:53:444 - info: [debug] Socket data being routed.
2015-04-24 02:49:53:444 - info: [debug] Got result from instruments: {"status":0,"value":{"ELEMENT":"0"}}
2015-04-24 02:49:53:445 - info: [debug] Responding to client with success: {"status":0,"value":{"ELEMENT":"0"},"sessionId":"ad96edc6-92b4-4b29-a2fc-d98281c83664"}
2015-04-24 02:49:53:445 - info: <-- POST /wd/hub/session/ad96edc6-92b4-4b29-a2fc-d98281c83664/element 200 1096.855 ms - 87 {"status":0,"value":{"ELEMENT":"0"},"sessionId":"ad96edc6-92b4-4b29-a2fc-d98281c83664"}
2015-04-24 02:49:53:448 - info: --> POST /wd/hub/session/ad96edc6-92b4-4b29-a2fc-d98281c83664/element/0/click {"sessionId":"ad96edc6-92b4-4b29-a2fc-d98281c83664","id":"0"}
2015-04-24 02:49:53:448 - info: [debug] Pushing command to appium work queue: "au.tapById('0')"
2015-04-24 02:49:53:448 - info: [debug] Sending command to instruments: au.tapById('0')
2015-04-24 02:49:54:433 - info: [debug] [INST] 2015-04-24 02:49:55 +0000 Debug: Got new command 4 from instruments: au.tapById('0')
2015-04-24 02:49:54:435 - info: [debug] [INST] 2015-04-24 02:49:55 +0000 Debug: evaluating au.tapById('0')
2015-04-24 02:49:54:437 - info: [debug] [INST] 2015-04-24 02:49:55 +0000 Debug: UIATextField.tap()
2015-04-24 02:49:54:679 - info: [debug] Socket data received (25 bytes)
2015-04-24 02:49:54:680 - info: [debug] Socket data being routed.
2015-04-24 02:49:54:680 - info: [debug] Got result from instruments: {"status":0,"value":""}
2015-04-24 02:49:54:681 - info: [debug] Responding to client with success: {"status":0,"value":"","sessionId":"ad96edc6-92b4-4b29-a2fc-d98281c83664"}
2015-04-24 02:49:54:681 - info: <-- POST /wd/hub/session/ad96edc6-92b4-4b29-a2fc-d98281c83664/element/0/click 200 1233.742 ms - 74 {"status":0,"value":"","sessionId":"ad96edc6-92b4-4b29-a2fc-d98281c83664"}

#8 楼 @fanfaneve 这个是 instrument 内部的 1s delay,详细可见:https://github.com/facebook/instruments-without-delay
appium 启动时加上 --native-instruments-lib false 可以去掉这个 delay 。你在 mac 下用 appium.app 的话这个 delay 默认是加上的。

#9 楼 @chenhengjie123
非常感谢,另外我还想问一下,appium.app 就是指的下载 appium.dmg 安装后的应用是吧?我用这个可以录制脚本,但是始终没有找到打开脚本运行的按钮,请问要怎么在 appium.app 中运行脚本?
如果我理解有误,那么你说的用 appium.app 指的是什么?

对, appium.app 就是 appium.dmg 里面那个应用。
运行脚本就是把代码拷到一个文件里面然后运行那个文件啊。
我不大记得 appium.app 有没有重放功能了。。。你可以找一下。

#9 楼 @chenhengjie123
启动 appium 的时候
appium -U 838ea3943db8c9a39c8db92d99f753d3006caf45 --app com.Alps.TestApp --native-instruments-lib false --log-timestamp
无法运行,说 “appium: error: Unrecognized arguments: false.”。貌似--native-instruments-lib 是不能带参数的。但是如果不带参数执行,这个配置又是 true:
[debug] Non-default server args: {"app":"com.Alps.TestApp","udid":"838ea3943db8c9a39c8db92d99f753d3006caf45","logTimestamp":true,"nativeInstrumentsLib":true}
请问下这个配置到底要怎么用啊?

按照 appium 官方的说法,加上 --native-instruments-lib 会有 delay,不加上的话默认是去掉 delay 的。
或者你在用例初始化 driver 的 Capability 里面加上 nativeInstrumentsLib:true 试试(这不是实际代码,只是表达这个意思)?
参考官网这里的说明:http://appium.io/slate/en/v1.3.6/?python#ios-only

#13 楼 @chenhengjie123

我测试的 app 中有一个选择城市的页面,这个页面可以向下滚动,每次执行到这个页面时,appium 就会先把所有的页面元素获取出来,包括向下滚动才能看到的元素。
由于元素非常多,需要 1 分钟才能获取完成,这个速度简直不能忍,有没有什么办法可以让 appium 只获取当前屏幕的元素吗?我记得 android 是只能获取当前屏幕的。

#14 楼 @sunrise 你指的是 iOS 是吧?
iOS 确实会先获取所有元素,但能否只获取当前屏幕元素这个我要回去看看源码才能回答你,现在我确定不了。

#15 楼 @chenhengjie123 是 IOS 的,谢谢了。

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