仅此一招,教你搞定Appium性能低,轻松玩转Appium

众所周知,appium和selenium使用的都是客户/服务架构,它的特色是在客户端写测试指令,在服务端执行。这种架构有两大优点:

1、跨语言,可以使用任何语言编写Appium代码;

2、可以构建大型私有或公有的Appium设备云。

这种架构也存在致命的缺点:降低性能。客户/服务架构用网络传输测试指令,这必然会受到网络延迟的影响,甚至天气不好也会波及。

网络太不可靠了,总会导致意想不到的卡顿、请求失败等等。这意味着你在本地跑代码时很完美,但传输到Appium云去运行时,可能完全不同,可能导致代码高度脆弱,甚至测试失败。

最重要的是,很多人不是直接使用Appium命令,而是一些框架。那些基于Appium的封装工具(对Appium命令进行了封装,存在过度使用的情况)。

比如,我看到有测试用5~10个请求去找一个元素,仅仅为了检索元素是否可用,我觉得这个方法不好。它会让脚本在云环境上的执行时间存在巨大差异。

除了网速慢,网络延迟也是一个杀手。比如你想执行命令A,之后立刻执行命令B,基本不可能使用网络来实现这个功能(B需要延迟才能到达Appium云服务器,不可能紧接着命令A马上执行)。

于是,W3C WebDriver规范团队想出了一个办法,创造新的Actions API(把整个action chain编码成一个API去调用),一旦action开始,链可能需要几秒或几分钟才能实际执行

(原文:even though the chain might take seconds or minutes to actually execute once the action begins.)。



使用Execute Driver Script
Appium团队已经做了同样的事情,不仅仅actions,甚至是任何Appium命令。允许在一个Appium命令中打包其它Appium命令。所有这些命令都将在Appium服务器上执行,因此不会受到网络延迟的影响。它是如何运作的?显然这很神奇!比如,我们在Java客户端中编写下面这个测试脚本:

@Test

p

ublic void testLoginNormally() {
    driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
    driver.findElement(MobileBy.AccessibilityId("Login Screen")).click();
    driver.findElement(MobileBy.AccessibilityId("username")).sendKeys("alice");
    driver.findElement(MobileBy.AccessibilityId("password")).sendKeys("mypassword");
    driver.findElement(MobileBy.AccessibilityId("loginBtn")).click();
    driver.findElement(By.xpath("//*[@text='Logout']")).click();
}

这是一个简单的登录/注销功能。我们可以使用ExecuteDriverScript命令一次性批量运行所有这些命令:

@Test

public void testLoginWithExecute() {

        driver.executeDriverScript(

            “await driver.setImplicitTimeout(10000);\n” +

            “await (await driver.$(‘~Login Screen’)).click();\n” +

            “await (await driver.$(‘~username’)).setValue(‘alice’);\n” +

            “await (await driver.$(‘~password’)).setValue(‘mypassword’);\n” +

            “await (await driver.$(‘~loginBtn’)).click();\n” +

            “await (await driver.$(‘//*[@text=\”Logout\”]’)).click();\n”);

}

这到底是怎么回事?它把Appium客户端的代码包裹到了字符串里,Appium团队讨论了许多方法,他们一致认为灵活性至关重要。

因此Execute Driver Script命令的参数是一个字符串(字符串使用起来更灵活),表示要在当前运行的Appium session中执行的JavaScript代码。该字符串最终由Appium服务器执行。

哇哦!这么做显然会引发远程代码执行漏洞(remote code execution vulnerability,比如在ExecuteDriverScript中输入获取账号密码,然后让服务器来执行)!所以我们需要谈谈安全问题。

首先,服务器必须指令参数才能启用Execute Driver Script

(原文:the server must be started in a special mode that allows this feature explicitly:)

appium –allow-insecure=execute_driver_script

其次,所有代码都在NodeJS VM中运行,这意味着它无法干扰Appium主程序。

实际上,我们可以严格控制执行代码可以访问什么方法。除了driver object之外,只提供访问权限。这个driver object是什么?它是WebdriverIO session object的一个实例。您可以WebdriverIO API和所有JavaScript语法!

这也正好解释了上面的代码,比如代码中driver.$ 相当于findElement,而代码中的〜表示ID定位。您还可以在字符串中返回文本,数据甚至元素,这些结果在父脚本中也可以使用。


使用Execute Driver Script

我想了解Execute Driver Script对测试执行时间的影响,因此我在支持此功能的Appium云提供商上进行了大量实验:HeadSpin(感谢HeadSpin) 。我的测试结果(客户端位置在Vancouver, Canada):

ServerUsing ExecuteDriver?Avg Test TimeAvg CommandTimeAvg Speedup
LocalhostNo49.12s0.55s
LocalhostYes48.71s0.54s0.8%
Mountain View, CANo72.53s0.81s
Mountain View, CAYes43.15s0.48s40.5%
Tokyo, JapanNo102.03s1.13s
Tokyo, JapanYes42.10s0.47s58.74%

分析

如果在本地执行,使用Execute Driver Script 并不会带来太多改进。这也很好理解,当客户端和服务器使用相同的网络接口时,基本上没有时间丢失的延迟。但是当Appium服务器位于其他地方时,进步就特别大。

Mountain View, CA离我在Vancouver的办公室要近一些,而 Tokyo离我的办公室则远一些,数据上的差异接近30%(Tokyo的平均时间更长)。这种差异首要问题是延迟,延迟加深了client/server model中存在的问题。比如命令很多时(每个测试有90个命令),测试时间大约30秒。

当我使用Execute Driver Script时,所有的90个命令都包含在一个批处理中,结果显示测试时间降低。由于我只进行了一次网络调用,因地理分布引起的延迟变得可以忽略不计,将测试行为时间缩短了40-60%!当然,此功能也受其它因素影响,包括批处理调用中输入的命令数等等……我也不建议将每个命令都填充到 Execute Driver Script,这里仅演示可能的性能改进。


测试方法

  • 这些测试是在HeadSpin在世界各地的真实网络上运行,并且使用真实的Android设备上,这些设备位于加州山景城和日本东京。(在本地,测试则使用我自己的笔记本电脑,运行手机模拟器和Appium服务器,因此与真实设备有些不同)
  • 对于每个测试条件(不同位置,是否使用Execute Driver Script),运行了15个不同的测试。
  • 每个测试包括重复登录和注销5次。
  • Appium命令的总数(不计算会话开始和退出)是每次测试90个,这意味着每个测试条件总共为1,350个。
  • 表中的数字会丢弃会话开始和退出时间,仅计算会话中的测试时间(如果你的时间主要集中在会话开始上,有非常少的命令,那么本篇文章对您用处不大)。



总结
Execute Driver Script 是新的Appium功能,在分布式测试时尤其有用。如果云服务器或设备位于世界各地,则每个命令将花费很长时间(甚至长于服务器关闭命令)。设备越远,命令执行时间就越长。管理员可以选择打开Appium中的Execute Driver Script,以允许其用户批量命令,这样可以避免与服务器进行大量不必要的延迟,为用户提供了很多优势,减少了延迟成本。当然,这是一项高级功能,您只应该用它来解决具体问题!
如果您想查看项目的java代码,可以在GitHub上查看:https://github.com/cloudgrey-io/appiumpro/blob/master/java/src/test/java/Edition085_Execute_Driver_Script.java。

其他Appium客户端也支持这个新命令,包括WebdriverIO(所以你可以使用WebdriverIO-ception!)

非常感谢HeadSpin启用该功能并让我使用设备,因此我可以为本文收集数据。

Cheers,

Jonathan & Jonah

翻译:若桐