中文Appium API 文档

该文档是Testerhome官方翻译的
源地址:https://github.com/appium/appium/tree/master/docs/cn
官方网站上的:http://appium.io/slate/cn/master/?ruby#about-appiumjavascript

中文Appium API 文档php

第一章:关于appium
1.1 appium客户端
客户端类库列表及Appium服务端支持css

这些类库封装了标准Selenium客户端类库,为用户提供全部常见的JSON 格式selenium命令以及额外的移动设备控制相关的命令,如多点触控手势和屏幕朝向。html

Appium客户端类库实现了Mobile JSON Wire Protocol(一个标准协议的官方扩展草稿)和W3C Webdriver spec(一个传输不可预知的自动化协议,该协议定义了MultiAction 接口)的元素。java

Appium 服务端定义了官方协议的扩展,为Appium 用户提供了方便的接口来执行各类设备动做,例如在测试过程当中安装/卸载app。这就是为何咱们须要Appium 特定的客户端,而不是通用的Selenium 客户端。固然,Appium 客户端类库只是增长了一些功能,而实际上这些功能就是简单的扩展了Selenium 客户端,因此他们仍然能够用来运行通用的selenium会话。
语言/框架 Github版本库以及安装指南
Ruby https://github.com/appium/ruby_lib
Python https://github.com/appium/python-client
Java https://github.com/appium/java-client
JavaScript (Node.js) https://github.com/admc/wd
Objective C https://github.com/appium/selenium-objective-c
PHP https://github.com/appium/php-client
C# (.NET) https://github.com/appium/appium-dotnet-driver
RobotFramework https://github.com/jollychang/robotframework-appiumlibrarynode

1.2 appium介绍
Appium 介绍python

Appium 是一个自动化测试开源工具,支持 iOS 平台和 Android 平台上的原生应用,web 应用和混合应用。linux

所谓的“移动原生应用”是指那些用 iOS 或者 Android SDK 写的应用。所谓的“移动 web 应用”是指使用移动浏览器访问的应用(Appium 支持 iOS 上的 Safari 和 Android 上的 Chrome)。所谓的“混合应用”是指原生代码封装网页视图——原生代码和 web 内容交互。好比,像 Phonegap,能够帮助开发者使用网页技术开发应用,而后用原生代码封装,这些就是混合应用。android

重要的是,Appium 是一个跨平台的工具:它容许测试人员在不一样的平台(iOS,Android)使用同一套API来写自动化测试脚本,这样大大增长了 iOS 和 Android 测试套件间代码的复用性。ios

想知道 Appium 如何支持平台,版本和自动化形态的详细信息,请参见platform support doc。
Appium 的理念

为了知足移动自动化需求,Appium 遵循着一种哲学,重点体现于如下4个需求:

你无需为了自动化,而从新编译或者修改你的应用。
你没必要局限于某种语言或者框架来写和运行测试脚本。
一个移动自动化的框架不该该在接口上重复造轮子。(移动自动化的接口应该统一)
不管是精神上,仍是名义上,都必须开源。

Appium 设计

那么 Appium 架构是如何实现这个哲学呢?为了知足第一条,Appium 真正的工做引擎实际上是第三方自动化框架。这样,咱们就不需在你的应用里植入 Appium 相关或者第三方的代码。这意味着你测试使用的应用与最终发布的应用并没有二致。咱们使用如下的第三方框架:

iOS: 苹果的 UIAutomation
Android 4.2+: Google's UiAutomator
Android 2.3+: Google's Instrumentation. (Instrumentation由单独的项目Selendroid提供支持 )

为了知足第二点,咱们把这些第三方框架封装成一套 API,WebDriver API.WebDriver(也就是 "Selenium WebDriver") 指定了客户端到服务端的协议。
(参见 JSON Wire Protocol)。使用这种客户端-服务端的架构,咱们可使用任何语言来编写客户端,向服务端发送恰当的 HTTP 请求。
目前已经实现了大多数流行语言版本的客户端,这意味着你可使用任何测试套件或者测试框架。客户端库就是简单的HTTP 客户,能够以任何你喜欢的方式潜入你的代码。换句话说,Appium 和 WebDriver 客户端不是技术意义上的“测试框架”,而是“自动化库”。你能够在你的测试环境中随意使用这些自动化库!

事实上 WebDriver 已经成为 web 浏览器自动化的标准,也成了 W3C 的标准 —— W3C Working Draft。咱们又何须为移动作一个彻底不一样的呢?因此咱们扩充了WebDriver 的协议,在原有的基础上添加移动自动化相关的 API 方法,这也知足了第三条理念。

第四条就不用说了,Appium 是开源的。
Appium 概念

C/S 架构<br/>
Appium 的核心是一个 web 服务器,它提供了一套 REST 的接口。它收到客户端的链接,监听到命令,接着在移动设备上执行这些命令,而后将执行结果放在 HTTP响应中返还给客户端。事实上,这种客户端/服务端的架构给予了许多的可能性:好比咱们可使用任何实现了该客户端的语言来写咱们的测试代码。好比咱们能够把服务端放在不一样
的机器上。好比咱们能够只写测试代码,而后使用像 Sauce Labs 这样的云服务来解释命令。

Session<br/>
自动化始终围绕一个session进行,客户端初始化一个seesion(会话)来与服务端交互,不一样的语言有不一样的实现方式,可是他们最终都是发送为一个POST请求给服务端,请求中包含一个JSON对象,被称做“desired capabilities”。此时,服务端就会开启一个自动化的 session,而后返回一个 session ID,session ID将会被用户发送后续的命令。

Desired Capabilities<br/>
Desired capabilities 是一些键值对的集合 (好比,一个 map 或者 hash),客户端将这些键值对发给服务端,告诉服务端咱们想要怎么测试。好比,咱们能够把platformName capability 设置为 iOS,告诉 Appium 服务端,咱们想要一个iOS 的 session,而不是一个 Android 的。咱们也能够设置 safariAllowPopups capability 为 true,确保在 Safari 自动化 session 中,咱们可使用 javascript 来打开新窗口。参见 capabilities 文档,查看完整的 capabilities 列表。

Appium Server<br/>
Appium server 是用 Node.js 写的。咱们能够用源码编译或者从 NPM 直接安装。

Appium 服务端<br/>

Appium 服务端有不少语言库 Java, Ruby, Python, PHP, JavaScript 和 C#,这些库都实现了
Appium 对 WebDriver 协议的扩展。当使用 Appium 的时候,你只需使用这些库代替常规的 WebDriver 库就能够了。
你能够从这里看到全部的库的列表。

Appium.app, Appium.exe<br/>

咱们提供了 GUI 封装的 Appium 服务端下载,它封装了运行 Appium服务端的全部依赖,而不须要担忧怎样安装Node.js。其中还包括一个Inspector工具,能够帮助你检查应用的界面层级,这样写测试用例时更方便。
Getting Started

恭喜!你如今有足够的知识来使用 Appium 了。 来咱们回到 getting started doc 继续了解更加
细节的需求和指南。

第二章:进阶指南
2.1 selenium配置
Selenium Grid

使用 <b>"--nodeconfig"</b> 服务器参数,你能够在本地 selenium grid 里注册你的 appium 服务器。

> node . -V --nodeconfig /path/to/nodeconfig.json

在 node 的配置文件里,你须要定义 <b>"browserName"</b>,<b>"version"</b> 和 <b>"platform"</b>。
基于这些参数,selenium grid 会将你的测试定向到正确的设备上去。你还须要配置你的 <b>host</b> 详细信息和
<b>selenium grid</b> 的详细信息。你能够在 <a href="http://code.google.com/p/selenium/source/browse/java/server/src/org/openqa/grid/common/defaults/GridParameters.properties">这里</a> 找到详细的参数列表和描述信息。

一旦你启动了 appium 服务器而且在 grid 里注册了信息,你会在 grid 控制台发现你的设备:

"http://<b><grid-ip-adress></b>:<b><grid-port></b>/grid/console"
Grid 配置文件例子

{
"capabilities":
[
{
"browserName": "<e.g._iPhone5_or_iPad4>",
"version":"<version_of_iOS_e.g._6.1>",
"maxInstances": 1,
"platform":"<platform_e.g._MAC_or_ANDROID>"
}
],
"configuration":
{
"cleanUpCycle":2000,
"timeout":30000,
"proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy",
"url":"http://<host_name_appium_server_or_ip-address_appium_server>:<appium_port>/wd/hub",
"maxSession": 1,
"register": true,
"registerCycle": 5000,
"hubPort": <grid_port>,
"hubHost": "<Grid_host_name_or_grid_ip-address>"
}
}

能够在 <a href="http://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/Platform.html">这里</a>查看有效的 platform 参数。
若是没有给出url、host和 port,配置会自动指向本地:whatever-port-Appium-started-on。
若是你的Appium服务和Selenium Grid服务没有运行在同一台机器上,为确保Selenium Grid链接正常,请在你的host & url docs上使用外部其它名称或IP地址,而非localhost 和 127.0.0.1

2.2 自动化混合应用
自动化混合应用

Appium 其中一个理念就是你不能为了测试应用而修改应用。为了符合这个方法学,咱们可使用 Selenium 测试传统 web 应用的方法来测试混合 web 应用 (好比,iOS 应用里的元素 "UIWebView" ),这是有可能的。这里会有一些技术性的复杂,Appium 须要知道你是想测试原生部分呢仍是web部分。幸运的是,咱们还能遵照 WebDriver 的协议。

混合 iOS 应用
混合 Android 应用

自动化混合 iOS 应用

在你的 Appium 测试里,你须要如下几步来和 web 页面交涉:

前往到应用里 web 视图激活的部分。
调用 GET session/:sessionId/window_handles
这会返回一个咱们能访问的 web 视图的 id 的列表。
使用你想访问的这个 web 视图的 id 做为参数,调用 POST session/:sessionId/window
(这会将你的 Appium session 放入一个模式, 在这个模式下,全部的命令都会被解释成自动化web视图而不是原生的部分。好比,当你运行 getElementByTagName,它会在 web 视图的 DOM 上操做,而不是返回 UIAElements。固然,一个 Webdriver 的方法只能在一个上下文中有意义,因此若是在错误的上下文,你会收到错误信息。)
若是你想中止 web 视图的自动化,回到原生部分,你能够简单地使用 execute_script 调用 "mobile: leaveWebView" 方法来离开 web 层。

在 iOS 真机上运行

appium 使用一个远程调试器创建链接来实现和 web 视图的交互。当在模拟器上执行下面例子的时候,咱们能够直接创建链接,由于模拟器和 appium 服务器在同一台机器上。

当在真机上运行用例时,appium 没法直接访问 web 视图,因此咱们须要经过 USB 线缆来创建链接。咱们使用 ios-webkit-debugger-proxy创建链接。

使用 brew 安装最新的 ios-webkit-debug-proxy。在终端运行一下命令:

# 若是你没有安装 brew 的话,先安装 brew。
> ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go/install)"
> brew update
> brew install ios-webkit-debug-proxy

你也能够经过 git 克隆项目来本身安装最新版本:

# Please be aware that this will install the proxy with the latest code (and not a tagged version).
> git clone https://github.com/google/ios-webkit-debug-proxy.git
> cd ios-webkit-debug-proxy
> ./autogen.sh
> ./configure
> make
> sudo make install

一旦安装好了, 你就能够启动代理:

# 将udid替换成你的设备的udid。确保端口 27753 没有被占用
# remote-debugger 将会使用这个端口。
> ios_webkit_debug_proxy -c 0e4b2f612b65e98c1d07d22ee08678130d345429:27753 -d

<b>注意:</b> 这个 ios-webkit-debug-proxy 须要 <b>"web inspector"</b> 打开着以便创建链接。在 <b> settings > safari > advanced </b> 里打开它。请注意 web inspector <b>在 iOS6 时候加入的</b> 之前的版本没有。
Wd.js Code example

// 假设咱们已经有一个初始化好了的 `driver` 对象。
driver.elementByName('Web, Use of UIWebView', function(err, el) { // 找到按钮,打开 web 视图
el.click(function(err) { // 引导到 UIWebView
driver.windowHandles(function(err, handles) { // 获得能访问的视图列表。
driver.window(handles[0], function(err) { // 由于只有一个,因此选择第一个。
driver.elementsByCss('.some-class', function(err, els) { // 经过 css 拿到元素。
els.length.should.be.above(0); // 确定有元素。
els[0].text(function(elText) { // 获得第一个元素的文本。
elText.should.eql("My very own text"); // 比较匹配文本。
driver.execute("mobile: leaveWebView", function(err) { // 离开web视图上下文。
// 若是你想的话,作一些原生应用的操做。
driver.quit(); // 退出。
});
});
});
});
});
});
});

想看到具体的上下文,请看该node 的例子
*咱们正在完善 web 视图下面的方法。加入咱们!

Wd.java 代码例子

//配置 webdriver 并启动 webview 应用。
DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
desiredCapabilities.setCapability("device", "iPhone Simulator");
desiredCapabilities.setCapability("app", "http://appium.s3.amazonaws.com/WebViewApp6.0.app.zip");
URL url = new URL("http://127.0.0.1:4723/wd/hub");
RemoteWebDriver remoteWebDriver = new RemoteWebDriver(url, desiredCapabilities);

// 切换到最新的web视图
for(String winHandle : remoteWebDriver.getWindowHandles()){
remoteWebDriver.switchTo().window(winHandle);
}

//在 guinea-pig 页面用 id 和 元素交互。
WebElement div = remoteWebDriver.findElement(By.id("i_am_an_id"));
Assert.assertEquals("I am a div", div.getText()); //验证获得的文本是否正确。
remoteWebDriver.findElement(By.id("comments")).sendKeys("My comment"); //填写评论。

//离开 webview,回到原生应用。
remoteWebDriver.executeScript("mobile: leaveWebView");

//关闭应用。
remoteWebDriver.quit();

Wd.rb cucumber 的例子

TEST_NAME = "Example Ruby Test"
SERVER_URL = "http://127.0.0.1:4723/wd/hub"
APP_PATH = "https://dl.dropboxusercontent.com/s/123456789101112/ts_ios.zip"
capabilities =
{
'browserName' => 'iOS 6.0',
'platform' => 'Mac 10.8',
'device' => 'iPhone Simulator',
'app' => APP_PATH,
'name' => TEST_NAME
}
@driver = Selenium::WebDriver.for(:remote, :desired_capabilities => capabilities, :url => SERVER_URL)

## 这里切换到最近一个窗口是由于在咱们的例子里这个窗口一直是 webview。其余的用例里,你须要本身指定。
## 运行 @driver.window_handles,查看 appium 的日志,找出到底哪一个窗口是你要的,而后找出相关的数字。
## 而后用 @driver.switch_to_window(number),切换过去。

Given(/^I switch to webview$/) do
webview = @driver.window_handles.last
@driver.switch_to.window(webview)
end

Given(/^I switch out of webview$/) do
@driver.execute_script("mobile: leaveWebView")
end

# 你可使用 CSS 选择器在你的 webview 里来选择元素

And(/^I click a webview button $/) do
@driver.find_element(:css, ".green_button").click
end

用 ruby 调试 web 视图:

我在个人帮助类里建立了一个快速方法来定位web元素,不管它在哪个窗口视图。
(这很是有帮助,特别是你的 webview 的 id 变化或者你用同一份代码来测试 Android 和 iOS。)
https://gist.github.com/feelobot/7309729
自动化混合 Android 应用

Appium 经过 Chromedriver 内建混合应用支持。Appium 也可使用 Selendroid 作为 4.4 以前的设备对 webview 支持的背部引擎。(你须要在 desired capability 里指定 "device": "selendroid")。而后:

前往你应用里 web 视图激活的部分。
用 "WEBVIEW" 作窗口句柄调用 POST session/:sessionId/window , 好比 driver.window("WEBVIEW")。
(这会将你的 Appium session 放入一个模式, 在这个模式下,全部的命令都会被解释成自动化web视图而不是原生的部分。好比,当你运行 getElementByTagName,它会在 web 视图的 DOM 上操做,而不是返回 UIAElements。固然,一个 Webdriver 的方法只能在一个上下文中有意义,因此若是在错误的上下文,你会收到错误信息。)
若是要中止web上下文里的自动化,回到原生部分的自动化,简单地使用 "NATIVE_APP" 调用 window 方法。好比 driver.window("NATIVE_APP")。

注意:咱们能够像上面说的,使用一样的策略。然而,Selendroid 使用 WEBVIEW/NATIVE_APP 窗口设置策略。 Appium 常规的混合支持也使用这种策略。
Wd.js 代码例子

// 假设咱们已经初始化了一个 `driver` 实例。
driver.window("WEBVIEW", function(err) { // 选择惟一的 WebView
driver.elementsByCss('.some-class', function(err, els) { // 经过 CSS 取得元素
els.length.should.be.above(0); // 验证元素存在
els[0].text(function(elText) { // 获得第一个元素的文本
elText.should.eql("My very own text"); // 验证文本内容
driver.window("NATIVE_APP", function(err) { // 离开 webview 上下文
// 能够作些原生应用的测试
driver.quit(); // 关闭 webdriver
});
});
});
});

Wd.java 代码例子

//配置 webdriver 并启动 webview 应用。
DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
desiredCapabilities.setCapability("device", "Selendroid");
desiredCapabilities.setCapability("app", "/path/to/some.apk");
URL url = new URL("http://127.0.0.1:4723/wd/hub");
RemoteWebDriver remoteWebDriver = new RemoteWebDriver(url, desiredCapabilities);

// 切换到最新的web视图
remoteWebDriver.switchTo().window("WEBVIEW");

//在 guinea-pig 页面用 id 和 元素交互。
WebElement div = remoteWebDriver.findElement(By.id("i_am_an_id"));
Assert.assertEquals("I am a div", div.getText()); //验证获得的文本是否正确。
remoteWebDriver.findElement(By.id("comments")).sendKeys("My comment"); //填写评论。

//离开 webview,回到原生应用。
remoteWebDriver.switchTo().window("NATIVE_APP");

//关闭应用。
remoteWebDriver.quit();

2.3 用例迁移
把appium 0.18.x上的测试用例集迁移到appium1.x上

Appium 1.0 已经从先前的版本中移除了一部分过期的特性, 这个指导文档会帮助你了解使用Appium 1.0须要作的具体改变.
新的客户端库

你须要关注的最大的改变是利用新的appium的client libraries来替换原生的WebDriver ciients. 访问Appium client list 去寻找符合你本身编程语言的客户端库吧. 在每一个客户端的网站上均可以找到用于集成到你代码中的依赖库相关介绍和下载

基本上, 你须要作以下的改变(以Python做为例子)

from appium import webdriver

替换原来的:

from selenium import webdriver

新的适配参数

下面的适配参数将再也不使用
* device
* version

取而代之的是利用下面的配置参数

platformName ("iOS" 或者 "Android")
platformVersion (你但愿测试的os版本)
deviceName (你想用的设备, 好比 "iPhone Simulator")
automationName ("Selendroid" 若是你想使用Selendroid的话, 不然能够省略)

app 配置参数保持不变, 可是特指非浏览器的app, 若是你想使用相似Safari或者Chrome这样的浏览器, 你须要设置browserName. 这表明app和browserName是互斥的.

咱们把appium的配置参数都规范为驼峰拼写法(camelCase), 这表明着原来的app-package或者app-wait-activity如今会变成appPackage和appWaitActivity. 固然目前android的app package和activity都已是自动探测了, 大部分状况下你能够省略这两个配置项.
新的定位方式

咱们已经移除了下面的定位方式

name
tag name

咱们增长了accessibility_id定位方法去作过去name作的事情. 具体的细节还得跟你使用的Appium客户端库有关.

tag name已经被替换为class name. 因此想经过UI的类型来定位某个元素, 你须要使用class name定位方式

关于class name和xpath的定位方式: 如今须要使用完整的全类名, 这意味着若是你有一个以下的定位用的xpath

//table/cell/button

如今须要改为

//UIATableView/UIATableCell/UIAButton

若是是android的话, button须要改变成android.widget.Button

咱们也增长了以下的定位方式

-ios uiautomation
-android uiautomator

根据你使用的客户端去相应的使用新的定位方式
使用xml, 再也不是json了

App source方法先前返回JSON, 如今修改为返回XML. 因此若是你有代码是依赖解析app source的, 那么就须要更新
经过context支持混合应用, 再也不是window了

之前混合app的切换支持是经过"windows"

window_handles
window
switch_to.window

如今Appium支持"context" 概念了, 要得到当前环境下全部的上下文(contexts), 或者特定的context, 你能够用

driver.contexts
current = driver.context

在这些context之间切换, 可使用

driver.switch_to.context("WEBVIEW")

没有了execute_script("mobile: xxx")

全部的mobile:方法都已经被移除, 而且被替换为appium client libraries的原生方法. 这意味着若是一个方法调用原来的方式是
driver.execute("mobile: lock", [5])
如今须要更新为
driver.lock(5)
在这个地方lock已经变成了原生的客户端方法. 固然具体的调用细节在不一样的客户端库中的实现可能会有所差异.

特别须要注意的是, 手势(gesture)方法已经被替换为TouchAction / MultiAction API, 它容许更强大通用的组合手势的自动化. 能够参考你的客户端库的具体用法.

这就是所有啦, 祝迁移愉快

(文档由testerhome.com翻译, 欢迎更多热爱技术的同窗加入到翻译中来, We Love Appium)

2.4 appium设置
Settings

Settings 是 Appium 引入的一个新的概念。 它目前尚未被归入 Mobile JSON Wire Protocol 及 Webdriver 标准之中。

Settings 是一种用来配置 Appium 服务器的方式。

Settings 有如下特色:
- 可变的,它在同一会话中是能够被修改的。
- 惟一的,它在被测应用会话中是惟一的。 它在每建立一个新会话时会被重置。
- 可控的,它在自动化测试过程当中控制着 Appium 服务器的运行。 它们不会被用来控制被测应用或被测终端。

在 Android 环境中 以 ignoreUnimportantViews 设置举例,该参数在 Android 环境中能够被设置成忽略全部与当前视图无关的元素,它将使测试过程更加有效率。 然而当咱们但愿可以访问被忽略的元素时,咱们必须在将 ignoreUnimportantViews 设置成 true 后,从新修改为 false 。

另外也能够经过 Settings 配置让 Appium 忽略全部当前不可见的元素。

Settings 能够经过如下 API 方法进行配置:

POST /session/:sessionId/appium/settings

以 JSON 格式提交 key:value 键值对形式的Settings配置。

{
settings: {
ignoreUnimportantViews : true
}
}

GET /session/:sessionId/appium/settings

以 JSON 格式返回当前全部 Settings 配置。

{
ignoreUnimportantViews : true
}

其它 Settings 配置参考

"ignoreUnimportantViews" -该参数值为 true 或 false。 若是你但愿可以尽可能减小测试过程的交互确认过程,或但愿测试脚本能更快的执行,能够在 Android 终端环境下使用 setCompressedLayoutHeirarchy() 参数。它将忽略全部被标记为 IMPORTANT_FOR_ACCESSIBILITY_NO 或 IMPORTANT_FOR_ACCESSIBILITY_AUTO(以及那些被认为不是很重要的系统元素)的元素。

第三章:appium 设置
3.1 加速器管理
Intel® 硬件加速器管理

若是你发现android模拟器太慢, 而且你的系统运行在Intel® 的cpu上. 那么你能够尝试下HAXM, HAXM可以让你充分利用硬件虚拟化技术来加速android模拟器。

要安装HAXM, 你能够打开Android SDK Manager, 你能够在Extras中发现这个安装选项;
你能够在Intel官方网站找到全部相关的文档;
这将须要x86的模拟镜像;
利用Intel的包来安装HAXM; Android SDK Manager有时候会安装不成功,这主要取决于你安装的版本是否兼容。

3.2 android 设置
Android Setup

使用前,你须要安装node.js(版本大于等于0.10)。 请参照 instructions for your flavor of linux。

当node.js安装成功后,请安装 Android SDK。
运行'android' tool(位于SDK,tool文件目录下)。

运行'android' tool 来安装大于等于Level 17的API。

(若是你想从Appium的源码来运行,可在真机或者模拟器上用 Apache Ant 来编译bootstrap jar包)。

最后,将环境变量$ANDROID_HOME设置为 Android SDK 的路径。例如,若是你将Android SDK 解压到 /usr/local/adt/,你须要把这个路径加到你的shell环境变量中去:

export ANDROID_HOME="/usr/local/adt/sdk"

如今就能够启动Appium了!若是你在源码中运行Appium请运行
./reset.sh --android 版本从Appium checkout会安装全部的依赖。
老版本的额外安装

当android的版本是2.3到4.1的时候,appium用的是selendroid。 当它检测到时低版本时,它会自动应用Selendroid。可是须要配置一些额外的设置若是从source运行。

已经安装 Maven 3.1.1 或更新 (mvn)
运行 ./reset.sh --selendroid 从checkout的Appium源码

(运行Appium Android 测试)

在Linux上运行,启动一个API大于等于level17的AVD。 在源文件目录下运行 (appium) 在安装好 NPM, 或者 node。若是你选择的是从源代码方式运行。
参照 server documentation 来了解全部命令和参数。
注意

Android 加速模拟器须要存在,它有本身的局限性,若是想了解更多,请看这里 page。
若是你想运行任何Appium的测试,或者任何强大的命令,确保你的 hw.battery=yes 在 AVD's config.ini文件中。
Selendroid 须要你APP中的以下权限: <uses-permission android:name="android.**permission.INTERNET"/>, 若是你在使用selendroid或者低版本的android(如版本2.3到4.1),请确保你的App已设置internet权限。

3.3 部署iOS app 到手机上
部署iOS app 到手机上

准备在真机上执行appium测试, 须要以下准备:

用特殊的设备参数来构建app
使用 fruitstrap, 这是一个第三方程序,能够用来部署你构建的app到手机上

Xcodebuild 命令的参数:

新的参数运行指定设置. 参考 developer.apple.com:

xcodebuild [-project projectname] [-target targetname ...]
[-configuration configurationname] [-sdk [sdkfullpath | sdkname]]
[buildaction ...] [setting=value ...] [-userdefault=value ...]

这有一个资料来参考可用的设置

CODE_SIGN_IDENTITY (Code Signing Identity)
介绍: 标识符,指定一个签名。
例如: iPhone Developer

PROVISIONING_PROFILE 已经从可用的的命令中消失了,但仍是有必要设置的。

在xcodebuild命令中设置 "CODE_SIGN_IDENTITY" & "PROVISIONING_PROFILE":

xcodebuild -sdk <iphoneos> -target <target_name> -configuration <Debug> CODE_SIGN_IDENTITY="iPhone Developer: Mister Smith" PROVISIONING_PROFILE="XXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX"

成功的话, app会构建到以下目录 <app_dir>/build/<configuration>-iphoneos/<app_name>.app
用Fruitstrap进行部署

clone一个fruitstrap的fork版本在ghughes version ,这个已经再也不维护. 已确认该fork可用unprompted fork, 可是其它的听说也可用。

clone成功的话, 执行 make fruitstrap
而后, 而后复制生成的 fruitstrap到app的所在的目录或上级目录下。

运行fruitstrap 经过输入如下命令 (命令是否可用依赖于你fork的 fruitstrap):

./fruitstrap -d -b <PATH_TO_APP> -i <Device_UDID>

若是是为了持续集成,你能够发现颇有用的方法来记录fruitstrap命令行和日志文件中的记录, 像这样:

./fruitstrap -d -b <PATH_TO_APP> -i <Device_UDID> 2>&1 | tee fruit.out

在node服务启动前fruitstrap进行须要被结束, 一个方法是扫描fruitstrap的输出来得知app完成启动。 有一个有效的方法是经过一个Rakefile 和一个 go_device.sh 脚本:

bundle exec rake ci:fruit_deploy_app | while read line ; do
echo "$line" | grep "text to identify successful launch"
if [ $? = 0 ]
then
# Actions
echo "App finished launching: $line"
sleep 5
kill -9 `ps -aef | grep fruitstrap | grep -v grep | awk '{print $2}'`
fi
done

一旦fruitstrap的进程被结束, node 服务就能够启动而且appium测试能够被执行!

下一步:
在真机上运行appium

3.4 Android并发测试
Android并发测试

Appium提供了在一台设备上启动多个Android会话的方案,而这个方案须要你输入不一样的指令来启动多个Appium服务来实现。

启动多个Android会话的重要指令包括:

-p Appium的主要端口
-U 设备id
-bp Appium bootstrap端口
--chromedriver-port chromedriver端口(当使用了webviews或者chrome)
--selendroid-port selendroid端口(当使用了selendroid)

更多参数的解释详见 here。

若是咱们有两台设备,设备ID分别为43364和32456,咱们应该用下面的命令启动来两个不一样的Appium服务:

node . -p 4492 -bp 2251 -U 32456

node . -p 4491 -bp 2252 -U 43364

只要你的Appium和Appium bootstrap端口介于0和65536便可,而且保证是两个不一样的端口以便两个Appium服务不会监听相同的端口。确认你的-u参数绑定正确的设备ID。这可让Appium知道链接哪台设备,因此参数必定要准确。

若是你用了chromedriver或selendroid,不一样的服务要设置不一样的端口。
iOS并发测试

不幸的是,IOS不能进行本地并发测试。跟Android不同,IOS在同一时间只能启动一个版本的模拟器来运行多个测试。
若是你想在IOS上进行并发测试,你须要用到Sauce。只需上传你的Appium测试脚本到Sauce,它就能够按照你的设置执行多个IOS或Android的并发测试。在Sauce上执行测试的更多信息,详见here。

3.5 Appium支持的平台
Appium支持的平台

Appium支持不少的运行平台和测试方式(包括原生、混合应用、内嵌浏览器、真机、模拟器等)。这篇文档主要用来让你们明确在使用
Appimu的时候支持的平台版本和上述测试方式的必备条件。
iOS平台支持

请移步到Running on OS X: iOS 。这里介绍了在iOS系统下使用Appium的必备条件和安装说明。

版本号:6.1,7.0,以及7.1。
支持设备:iPhone模拟器,iPad模拟器以及iPhones和iPads真机。
是否支持原生应用:支持。同时支持模拟器中调试应用版本和正确签名的真机ipa。其余相关支持由苹果的UIAutomation框架提供。
是否支持内置移动浏览器:支持。Safari浏览器已经经过测试。对于真机,则须要安装调试工具ios-webkit-remote-debugger。很遗憾,对于Safari的原生界面的自动化是不支持的。更多信息请移步至mobile web doc 。
是否支持混合应用:支持。一样对于真机须要安装调试工具ios-webkit-remote-debugger,更多详情请移步至hybrid doc 查看详情。
是否支持在同一个session中执行多个应用的自动化:不支持。
是否支持同时再多个设备上执行自动化:不支持。
是否支持第三方提供应用:只支持在模拟器上有限的第三方应用(例如:喜爱设置、地图等)。
是否支持自定义的、非标准UI控件的自动化:仅支持不多一部分。最好对控件添加可识别信息,以方便对元素进行一些基础的自动化操做。

Android平台支持

请移步至 Running on OS X: Android,Running on Windows,或者Running on Linux 得到在不一样操做系统下android平台对appium的支持和安装配置文档。

支持版本:android 2.3平台及以上。
android 4.2平台及以上经过Appium自有的UiAutomator类库支持。默认在自动化后台。
从android 2.3到4.3平台,Appium是经过绑定Selendroid,实现自动化测试的,你能够到android开发社区的Instrumentation。(仪表盘)中查看相关介绍。Selendroid拥有一套不一样的命令行和不一样的profile文件(这部分差距正在逐步缩小)。要得到在后台运行自动化的权限,须要配置automationName 组件的值为 Selendroid。
支持的设备:Android模拟器和Android真机。
是否支持原生应用:支持。
是否支持内置移动浏览器:支持(除了使用Selendroid后台运行的状况)。经过代理方式绑定到Chromedriver来运行自动化测试。在android4.2和4.3版本中,只有在官方版本的谷歌浏览器或者Chromium下才能运行自动化测试。伴随着android 4.4+版本的出现。自动化测试则能够运行在内置浏览器的应用程序。可是须要在测试设备环境下安装Chrome/Chromium/浏览器。请移步至mobile web doc 获取更多详情。
是否支持混合应用: 支持。请移步至hybrid doc参考相关文档。
经过默认的Appium的后台支持android 4.4以上的版本。
经过Selendroid的后台支持android 2.3以上的版本。
是否支持在同一个session中执行多个应用的自动化:支持(可是不支持使用Selendroid后台的场景)。
是否支持同时再多个设备上执行自动化:支持,。尽管Appium必需要启动另外一个端口即经过添加参数的方式运行命令行,例如--port,--bootstrap-port(或者--selendroid-port)或者--chromedriver-port。更多详情请移步至server args doc。
是否支持第三方应用自动化:支持(可是不支持Selendroid后台运行的场景)。
是否支持自定义的、非标准UI控件的自动化:不支持。

3.6 Appium在真机上
Appium在真机上

Appium已经初步支持真机测试。

若是要在真机上执行测试,你将要作以下准备:

1.一个苹果的开发者ID和有效的开发者对应的配置文件和签名文件

2.一台iPad或者iPhone

你要测试的应用的源码

一台安装了XCode和XCode Command Line Developer Tools的Mac机器

Provisioning Profile

要在真机上测试就须要一个有效的iOS开发者的Distribution Certificate and Provisioning Profile。你能够在这个上面找到配置这些的相关信息Apple documentation

一样的,你还须要对你的应用签名,更多的信息能够查看sign your app.

你必须使用Xcode的执行按钮来安装你的应用
使用Appium运行你的测试

一旦你的设备和应用设置好了以后,你就可以用以下的命令在你的机器上执行测试:

node . -U <UDID> --app <bundle_id>

这将会启动Appium而且开始在真机上测试应用。
疑问解答思路

确认UDID已经正确的在xcode organizar或itunes中设置了。很长的字符串(20多个字符串) 0.确认你测试代码中的测试对象设备的设置
再次确认你从instruments启动你的自动化测试
确认instruments已经关闭

3.7 在 Linux 上运行 Appium
在 Linux 上运行 Appium
限制

若是你在 Linux 上使用 Appium, 那么你无法使用已经构建好的 '.app',那是为 OS X 准备的。 另外因为 Appium 在测试 iOS 应用时 依赖 OS X 特有的库, 因此你也没有办法测试在 Linux 上测试 iOS 应用。
配置

首先,安装版本高于或等于 0.8 的 nodejs。能够根据 instructions for your flavor of linux 进行安装。

安装好了 node.js 以后,安装 Android SDK。 你会须要运行 android adb 等工具,这些工具都在 SDK 里包含了, 你要作的是配置环境变量。固然你要确保你的 API level 大于等于 17。 你也须要使用 Ant 来构建 bootstrap jar 以便 Appium 使用它来测试 Android 应用。

最后, 设置 $ANDROID_HOME 为你的 Android SDK 的路径。好比, 你将 Android SDK 解压在 /usr/local/adt/, 那你就要将以下添加到你的 .bashrc 或 .zshrc 或 .bash_profile 等 shell 配置文件中去:

export ANDROID_HOME="/usr/local/adt/sdk

如今你能够运行 Appium 了, 在你 checkout 出来的 Appium 目录里, 运行 .reset.sh --android, 它会帮助你安装好全部的依赖。
运行 Appium

运行测试前, 你须要启动一个 API Level 大于等于 17 的 Android 模拟器或者链接一个系统是 4.1 以上的 Android 真机。而后在 Appium 目录运行

node .

你能够在 server documentation 找到全部的命令行参数。
备注

There exists a hardware accelerated emulator for android, it has it's own limitations. For more information you can check out this Android 有一些硬件加速的模拟器,这些模拟器有本身的限制。你能够在 page 找到更多的信息。
确保你使用的 AVD 里面的 config.ini 有这条指令 hw.battery=yes。

3.8 在 Mac OS X 上使用 Appium
在 Mac OS X 上使用 Appium

在 OS X 上, Appium 支持 iOS 和 Android 测试
系统配置 (iOS)

Appium 须要 Mac OS X 10.7, 推荐 10.8。 (通过测试, 10.9 也能工做。)
确保 Xcode 和 iOS SDK 都已经安装好了。 (当前 Appium 支持 Xcode 4.6.3/iOS 6.1 和 Xcode 5/iOS 7.0。 注意不推荐在基于 Xcode 5 下且低于 7.0 的 iOS 版本进行测试。 参照下篇能够获取更多信息)
你须要受权 iOS 模拟器的使用。若是你是经过 NPM 安装的 Appium,那么你能够运行 sudo authorize_ios (authorize_ios)是来自 Appium npm 包里的一个二进制执行文件。若是你是从源代码运行 Appium,那么你能够简单的使用 sudo grunt authorize。若是你使用Appium.app, 那你只要用界面来操做。
若是你使用的是Xcode 6,在启动Appium以前,你须要打开模拟器,而且在你须要进行输入文字的操做以前,必须先将输入法提早调出。你能够经过点击输入区域或经过快捷键command-K来将软键盘唤出。
Xcode 6中,有一个Devices的模块(command-shift-2可唤出)。你必须确保Appium 的capabilities参数中,所使用到的deviceName要存在于Devices里。换句话说,若是capabilities中的deviceName为"iPhone 5s",platformVersion为"8.0",那么你必须确保Devices中要存在那么一个设备是"iOS8系统的iPhone5s",不然Appium将不知道使用哪个设备进行测试。
在iOS8设置中的开发者选项里面,你能够打开或关闭UIAutomation。若是你的是iOS8设备,请在运行Appium以前,确保UIAutomation是打开状态的。

使用多种 iOS SDK 进行测试

Appium 使用苹果提供的 instruments 来启动 iOS 模拟器,默认它会使用当前安装的 Xcode 和该 Xcode 下安装好的最高版本的 iOS SDK。这就意味着若是你想测试 iOS 6.1, 可是你安装了 iOS 7.0, 那么 Appium 会强制使用 7.0 的模拟器。 惟一的方法就是安装多个Xcode,而后在安装不一样的 SDK。而后在启动 Appium 前,切换到你要测试的特定的版本。

另外,咱们发现 Xcode 5 上的 iOS 6.1 测试,会很慢并且不稳定。因此咱们推荐,若是要在 6.1 及 6.1 如下版本的 iOS 上进行测试,请使用 Xcode 4.6.3。若是要在 iOS 7.0 上测试,请使用 Xcode 5。假设咱们的 Xcode 5 在 /Applications/Xcode.app, Xcode 4.6 在 /Applications/Xcode-4.6.app,咱们就能够用下面的命令来切换到 Xcode 4.6 来为 iOS 6.1 测试作准备。

sudo xcode-select -switch /Applications/Xcode-4.6.app/Contents/Developer/

若是要回到 Xcode 5 的话,咱们再运行一次:

sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer/
系统配置 (Android)

在Mac OSX 上运行Android项目所须要的配置,与Linux的配置方法是一致的,请参考 Android setup docs。

3.9 在Windows上运行Appium
在Windows上运行Appium
局限性

若是你在windows上安装appium,你无法使用预编译专用于OS X的.app文件,你也将不能测试IOS apps,由于appium依赖OS X专用的库来支持IOS测试。这意味着你只能经过在mac上来运行IOS的app测试。这点限制挺大。
开始安装

安装nodejs 0.8版本及以上, 经过官方的安装程序来安装。

安装android的sdk包,(http://developer.android.com/sdk/index.html), 运行依赖sdk中的'android'工具。并确保你安装了Level17或以上的版本api。设置ANDROID_HOME系统变量为你的Android SDK路径,并把tools platform-tools两个目录加入到系统的Path路径里。由于这里面包含有一些执行命令

安装java的JDK,并设置JAVA_HOME 变量为你的JDK目录。

安装Apache Ant
或者直接使用Android Windows SDK自带的ant,地址在eclipse\plugins目录,你须要把这个目录加到你的系统PATH变量中

安装Apache Maven. 而且设置M2HOME和M2环境变量,把M2环境变量添加到你的系统PATH变量中。

安装Git. 确保你安装了windows下的Git,以即可以运行经常使用的command命令

如今,你已经下载安装了全部的依赖,开始运行
reset.bat
运行Appium

要在windows上运行测试用例,你须要先启动Android模拟器或者链接上一个API Level17以上的android真机。而后在命令行运行appium。
若是你是使用源码运行Appium的,请在你所安装的appium目录下执行node.js命令:

node .

备注

在windows系统下运行appium.app时,须要使用管理员权限;当你经过源码的形式运行Appium时,也须要使用管理员权限启动CMD。
在windows系统下运行Android项目时,启动Appium时请带上--no-reset或--full-reset命令。
有一个硬件加速模拟器用于android,可是它有本身的一些限制,若是你想了解更多,请参考页面
确保在你的AVD的config.ini中有一个配置项为hw.battery=yes

最简略的安装方式

出于对官方文档的尊重,我按照原文翻译,以下介绍个人安装心得。官方提到的一些工具,其实并不须要安装。
下面介绍我已经测试过的安装和使用过程
安装appium

安装nodejs

使用npm安装appium,npm install -g appium

运行appium

启动appium,直接运行appium 便可。
更新appium

经过npm install -g appium 来更新appium便可

若是有任何疑问,欢迎到testerhome.com来交流

3.10 Appium 故障排除
Appium 故障排除

当你遇到问题时,请不要急着将问题提交到Github,也不用急着发到appium-discuss discussion group,也许你能够在本文中找到答案。
常见问题解决办法

确保你的每个步骤都是遵循 入门指南 来作的。
确保你的系统配置正确。(例如:Xcode是否升级到了最新版本,Android SDK是否有设置到环境变量ANDROID_HOME中去。)
确保你的应用存放路径没有错误。

Appium.app运行出现问题的解决办法

升级Appium.app后从新打开便可解决。若是提示你不能升级,则须要从新下载Appium.app,下载地址:appium.io

经过源码启用Appium出现问题的解决办法

使用git pull拉取最新源码,确保运行的代码是当前最新版本。
针对你所自动化的平台,运行reset.sh命令:

命令 说明
./reset.sh # all
./reset.sh --ios # ios-only
./reset.sh --android # android-only
./reset.sh --selendroid # selendroid-only

当你须要下载以及构建测试应用时,运行reset.sh时你须要用到--dev指令。
你也可使用appium-doctor来自动检测你的环境依赖都是否正常。若是你是使用源码运行,则须要使用到bin/appium-doctor.js或node bin/appium-doctor.js。
当你将Android SDK升级到22后,可能出现以下错误: {ANDROID_HOME}/tools/ant/uibuild.xml:155: SDK does not have any Build Tools installed. 这是由于在Android SDK 22中,platform 和 build 工具被分拆到他们各自的SDK管理包中去了。你须要确保你的机器上正确安装了build-tools 和 platform-tools。

Android常见问题解决办法

确保 Android 模拟器启动并运行着。
出现设备链接问题时,运行adb kill-server && adb devices是很是有效的。它可以帮助重置和链接Android设备。
请确保环境变量 ANDROID_HOME 指向的是正确的Android SDK的路径。

IOS常见问题解决方案

确保Instruments.app是关闭的。
若是你是使用模拟器运行的,请不要将真机设备链接电脑。
确保模拟器或真机中,设置里面的accessibility辅助功能是关闭状态的。
确保App是编译在当前运行的模拟器上。
确保App是编译在合适的模拟器(或真机)上,否则会出现posix spawn的报错。(好比:运行在debug模式下的模拟器)
若是你曾经用 sudo 运行过 Appium, 你须要先删除/tmp/instruments_sock, 执行sudo rm /tmp/instruments_sock。而后在不适用SUDO的状况下再次启动Appium便可。
第一次运行Appium时,须要对Instruments进行受权。否则的话会常常弹出对话框要求你输入密码。若是你从源代码运行 Appium,你只需在主分支上运行sudo grunt authorize来回避该弹窗。若是用 npm 安装的话,运行 sudo authorize_ios 便可。注意,当你每次安装了新版本的xcode,你都须要重复以上操做。
若是检查路径正确,但仍然报 iOS Simulator failed to install the application.的错误的时候,请尝试重启你的电脑。

Webview/Hybrid/Safari 应用支持

确保真机上的'Web Inspector'为打开状态。
确保打开了Safari的开发模式。(Safari - Advance Preferences- Developer menu for simulators)
确保由client library提供的Appium命令-context可以正常得对contexts进行切换。
当你尝试打开代理的时候,出现以下错误:select_port() failed,请参考discussion

FirefoxOS常见问题解决办法

确保 Boot-to-Gecko 模拟器启动并运行着。
确保模拟器的屏幕是亮着并没有锁屏的(可能须要重启 B2G).

到社区寻求帮助

若经过上述方法你的问题依然没有获得解决,你能够:

若是你的 Appium 没法正常工做,而后错误信息不够清晰,欢迎加入 discussion group中发表你的问题,你的问题须要包括如下内容:

你是如何运行Appium的?(Appium.app, npm, source)
你使用的是什么操做系统?
你使用的是什么设备?版本是什么? (i.e. Android 4.4, or iOS 7.1)
你使用的是真机仍是模拟器?
给出你获得的客户端和服务端的出错日志 (好比,"个人Python代码中报了以下错误:balabala,在Appium server中的输出内容如连接中所示")
除了上述, 贴出 Appium 服务器端的输出也很是重要,特别是运行在 verbose 模式。这样咱们能够分析诊断问题在哪里。

若是你确信你发现的是一个BUG,请到issue tracker中提交一个issue,并将BUG的内容描述清楚。
已知问题

若是你从 Node 官网安装的 Node,那须要你使用 sudo 运行 npm。 但这么作并非很是理想。请尝试从 n 获取node 或运行brew install node来安装 。
Webview经过代理能够支持iOS真机设备,请参考discussion
有时候, iOS 的 UI 元素在定位到以后几毫秒会忽然变得无效。这会致使一个相似(null) cannot be tapped的错误。惟一的解决方法就是把finding-and-acting的代码放到 retry 块里。
若是你是经过MacPorts安装了Node和Npm,你必须确保MacPorts的bin文件夹已经被添加到环境变量PATH中去,否则Appium会出现难以找到可执行node的状况。

特定的错误
Action Error Resolution
Running reset.sh xcodebuild: error: SDK "iphonesimulator6.1" cannot be located 安装 iPhone 6.1 SDK 或者 使用单独的 SDK 构建 待测应用 好比: grunt buildApp:UICatalog:iphonesimulator5.1
Running reset.sh Warning: Task "setGitRev" not found. Use --force to continue. 使用git submodule update --init更新模块并再次运行reset.sh
Running reset.sh [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.3.2:compile (default-compile) on project selendroid-server: Compilation failure [ERROR] Failure executing javac, but could not parse the error: [ERROR] [ERROR] [ERROR] The system is out of resources. [ERROR] Consult the following stack trace for details. [ERROR] java.lang.StackOverflowError export MAVEN_OPTS="-Xms1024m -Xmx2048m -Xss2048k"
Running ios test [INST STDERR] posix spawn failure; aborting launch 你的应用没有正确编译在模拟器或真机上。
Running mobile safari test error: Could not prepare mobile safari with version '7.1' 你可能须要在此运行受权脚本以保证使iOS SDK文件为可写状态。 E.g., sudo authorize_ios

第四章:appium运行
4.1 从源码运行Appium
##从源码运行Appium

你想要从源码运行 Appium 并帮助修复 bug 和添加新的特性么?很好! fork 这个项目,作一点更改,而且发送一个请求吧!
另外,在工做以前请先看下咱们的代码风格指南。请在发送请求前,确保单元测试与功能测试都测试经过;
关于如何运行测试的更多信息,请继续阅读!
首先确保你阅读并遵循 README 中的安装说明。

###从源码配置Appium

Appium 的安装,包含在你的测试代码与设备/模拟器之间来回发送消息的 Appium 服务端,和一个用任何存在且兼容Appium的语言编写的测试脚本。
运行一个 Appium 服务器实例,而后进行你的测试。

快速开始的方式:

$ git clone https://github.com/appium/appium.git
$ cd appium
$ ./reset.sh
$ sudo ./bin/authorize-ios.js # for ios only
$ node .

Appium 开发环境搭建

确保你安装了 ant,maven,adb 而且将他们加入到了系统环境变量 PATH 中,与此同时你还须要安装 android-16 sdk(Selendroid) 和android-19 sdk。
从你本地仓库的命令行提示,使用下边的命令安装以下包(若是你没有使用homebrew包管理器安装 node,则你可能不得不使用 sudo 权限运行npm):

npm install -g mocha
npm install -g grunt-cli
node bin/appium-doctor.js --dev
./reset.sh --dev

前两个命令安装测试和构建工具(若是你已经经过 Homebrew 包管理器安装了 node.js 就不须要 sudo 了)。
第三个命令验证全部的依赖关系是否设置正确(因为依赖关系构建 Appium 不一样于简单的运行 Appium ),
第四个命令安装全部程序依赖关系和构建支持二进制文件和测试应用程序。
reset.sh 也是建议先从 master 上 pull 下改变后的内容再执行命令。
运行 reset.sh 加上 --dev 标志同时安装 git hooks 以确保代码质量在提交时是被保存过的。
此时,你能够启动 Appium 服务:

node .

查看完整的服务文档参数列表the server documentation

想要实现任务自动化,请检出Appium Grunt tasks来构建应用程序,安装程序,生成文档,等等。
搭建iOS运行环境

为了不启动 iOS apps 时弹出安全警告,你能够经过如下两种方法修改 /etc/authorization 文件:

手动将 /etc/authorization 文件中 <key>system.privilege.taskport<key/> 下紧跟 <allow-root> 的元素改为 <true/>。

运行如下grunt命令来自动修改 /etc/authorization 文件:

sudo ./bin/authorize-ios.js

而后再运行如下命令:

./reset.sh --ios --dev

如今你的 appium 实例已经准备就绪,运行 node . 来启动 appium server.
搭建android运行环境

Bootstrap 经过运行如下命令来启动 android:

./reset.sh --android --dev

若是你想运行Selendroid 来支持2.3这样的旧的android平台,运行如下命令:

./reset.sh --selendroid --dev

确保你有且只有一个 Android 模拟器或者真机在运行,举个例子,在其它的设备上运行此命令(假设 emulator 命令已经在你的 path 中了)需执行:

emulator -avd <MyAvdName>

如今你能够经过 node . 启动 Appium server 了。
确保更新到最新版本

因为 Appium 使用一些包的开发版本,因此常常安装新的 npm 包和升级不一样的包是颇有必要的。如下命令能够将全部平台上的包进行更新( --dev 标志会获取 npm dev 依赖和 Appium 测试套件中用到的应用程序)。当Appium提示版本更新时,你也能够用如下命令来更新:

./reset.sh --dev

或者你能够只更新指定的平台:

./reset.sh --ios --dev
./reset.sh --android --dev
./reset.sh --selendroid --dev

运行测试集

首先,看看咱们的文档普通状况下执行测试 ,
而后确保你的环境在对应的平台上已经搭建好了且与你所指望的那样。

当你的环境搭建好了以后而且你的代码是最新的,你能够经过如下的方式来运行单元测试:

grunt unit

你能够在所支持的平台上运行一些功能测试(确保后 Appium 用 node . 在另一个窗口中运行):

bin/test.sh

或者你能够经过运行 test.sh 来对指定的平台环境进行测试:

bin/test.sh --android
bin/test.sh --ios
bin/test.sh --ios7
bin/test.sh --ios71

在提交代码时,请运行 grunt 执行一些基本的测试和核对代码质量标准的更改,请注意,这可能会自动发生的,
若是你已经运行 reset.sh --dev ,这于你预先提交代码的操做所关联起来的。

grunt lint
> Running "newer:jshint" (newer) task
>
> Running "newer:jshint:files" (newer) task
> No newer files to process.
>
> Running "newer:jshint:test" (newer) task
> No newer files to process.
>
> Running "newer:jshint:examples" (newer) task
> No newer files to process.
>
> Running "jscs:files" (jscs) task
> >> 303 files without code style errors.

运行单独的测试

若是你有一个 Appium 服务监听,你能够经过 Mocha 来运行单独的测试文件,例如:

DEVICE=ios71 mocha -t 60000 -R spec test/functional/ios/testapp/simple.js

或者单独的测试集(例如,测试名称中的单词 "alert" )

DEVICE=ios6 mocha -t 60000 -R spec --grep "alert" test/functional/ios/uicatalog

对于 windows 操做系统,你能够用 set DEVICE=android 在 cmd 命令行的方式中运行以上全部测试集,例如:

set DEVICE=android
mocha -t 60000 -R spec test/functional/android/apidemos/alerts-specs.js

注意:对于安卓系统,你将须要一个屏幕大小为4.0(400x800)的模拟器/设备(emulator/device),有些测试集在不一样的屏幕大小下可能会失败。

DEVICE 必须设置为一个有效的值:ios71, ios6, android, selendroid

4.2 appium 开发环境搭建
##从源码运行Appium

你想要从源码运行 Appium 并帮助修复 bug 和添加新的特性么?很好! fork 这个项目,作一点更改,而且发送一个请求吧!
另外,在工做以前请先看下咱们的代码风格指南。请在发送请求前,确保单元测试与功能测试都测试经过;
关于如何运行测试的更多信息,请继续阅读!
首先确保你阅读并遵循 README 中的安装说明。

###从源码配置Appium

Appium 的安装,包含在你的测试代码与设备/模拟器之间来回发送消息的 Appium 服务端,和一个用任何存在且兼容Appium的语言编写的测试脚本。
运行一个 Appium 服务器实例,而后进行你的测试。

快速开始的方式:

$ git clone https://github.com/appium/appium.git
$ cd appium
$ ./reset.sh
$ sudo ./bin/authorize-ios.js # for ios only
$ node .

Appium 开发环境搭建

确保你安装了 ant,maven,adb 而且将他们加入到了系统环境变量 PATH 中,与此同时你还须要安装 android-16 sdk(Selendroid) 和android-19 sdk。
从你本地仓库的命令行提示,使用下边的命令安装以下包(若是你没有使用homebrew包管理器安装 node,则你可能不得不使用 sudo 权限运行npm):

npm install -g mocha
npm install -g grunt-cli
node bin/appium-doctor.js --dev
./reset.sh --dev

前两个命令安装测试和构建工具(若是你已经经过 Homebrew 包管理器安装了 node.js 就不须要 sudo 了)。
第三个命令验证全部的依赖关系是否设置正确(因为依赖关系构建 Appium 不一样于简单的运行 Appium ),
第四个命令安装全部程序依赖关系和构建支持二进制文件和测试应用程序。
reset.sh 也是建议先从 master 上 pull 下改变后的内容再执行命令。
运行 reset.sh 加上 --dev 标志同时安装 git hooks 以确保代码质量在提交时是被保存过的。
此时,你能够启动 Appium 服务:

node .

查看完整的服务文档参数列表the server documentation

想要实现任务自动化,请检出Appium Grunt tasks来构建应用程序,安装程序,生成文档,等等。
搭建iOS运行环境

为了不启动 iOS apps 时弹出安全警告,你能够经过如下两种方法修改 /etc/authorization 文件:

手动将 /etc/authorization 文件中 <key>system.privilege.taskport<key/> 下紧跟 <allow-root> 的元素改为 <true/>。

运行如下grunt命令来自动修改 /etc/authorization 文件:

sudo ./bin/authorize-ios.js

而后再运行如下命令:

./reset.sh --ios --dev

如今你的 appium 实例已经准备就绪,运行 node . 来启动 appium server.
搭建android运行环境

Bootstrap 经过运行如下命令来启动 android:

./reset.sh --android --dev

若是你想运行Selendroid 来支持2.3这样的旧的android平台,运行如下命令:

./reset.sh --selendroid --dev

确保你有且只有一个 Android 模拟器或者真机在运行,举个例子,在其它的设备上运行此命令(假设 emulator 命令已经在你的 path 中了)需执行:

emulator -avd <MyAvdName>

如今你能够经过 node . 启动 Appium server 了。
确保更新到最新版本

因为 Appium 使用一些包的开发版本,因此常常安装新的 npm 包和升级不一样的包是颇有必要的。如下命令能够将全部平台上的包进行更新( --dev 标志会获取 npm dev 依赖和 Appium 测试套件中用到的应用程序)。当Appium提示版本更新时,你也能够用如下命令来更新:

./reset.sh --dev

或者你能够只更新指定的平台:

./reset.sh --ios --dev
./reset.sh --android --dev
./reset.sh --selendroid --dev

运行测试集

首先,看看咱们的文档普通状况下执行测试 ,
而后确保你的环境在对应的平台上已经搭建好了且与你所指望的那样。

当你的环境搭建好了以后而且你的代码是最新的,你能够经过如下的方式来运行单元测试:

grunt unit

你能够在所支持的平台上运行一些功能测试(确保后 Appium 用 node . 在另一个窗口中运行):

bin/test.sh

或者你能够经过运行 test.sh 来对指定的平台环境进行测试:

bin/test.sh --android
bin/test.sh --ios
bin/test.sh --ios7
bin/test.sh --ios71

在提交代码时,请运行 grunt 执行一些基本的测试和核对代码质量标准的更改,请注意,这可能会自动发生的,
若是你已经运行 reset.sh --dev ,这于你预先提交代码的操做所关联起来的。

grunt lint
> Running "newer:jshint" (newer) task
>
> Running "newer:jshint:files" (newer) task
> No newer files to process.
>
> Running "newer:jshint:test" (newer) task
> No newer files to process.
>
> Running "newer:jshint:examples" (newer) task
> No newer files to process.
>
> Running "jscs:files" (jscs) task
> >> 303 files without code style errors.

运行单独的测试

若是你有一个 Appium 服务监听,你能够经过 Mocha 来运行单独的测试文件,例如:

DEVICE=ios71 mocha -t 60000 -R spec test/functional/ios/testapp/simple.js

或者单独的测试集(例如,测试名称中的单词 "alert" )

DEVICE=ios6 mocha -t 60000 -R spec --grep "alert" test/functional/ios/uicatalog

对于 windows 操做系统,你能够用 set DEVICE=android 在 cmd 命令行的方式中运行以上全部测试集,例如:

set DEVICE=android
mocha -t 60000 -R spec test/functional/android/apidemos/alerts-specs.js

注意:对于安卓系统,你将须要一个屏幕大小为4.0(400x800)的模拟器/设备(emulator/device),有些测试集在不一样的屏幕大小下可能会失败。

DEVICE 必须设置为一个有效的值:ios71, ios6, android, selendroid

4.3 Appium grunt 命令
Appium grunt 命令

Grunt 是 Node.js 的 Make! 咱们用它来自动化全部的 appium 开发任务。 下面就是你能作的:
任务 描述
grunt lint 运行 JSLint
grunt test 运行全部的测试
grunt functional 运行整个功能测试集
grunt ios 运行 iOS 功能测试集
grunt android 运行 Android 功能测试集
grunt selendroid 运行 selendroid 功能测试集
grunt firefoxos 运行 firefoxos 功能测试集
grunt unit 运行全部的单元测试
grunt getSampleCode 下载示例代码和示例app. 接受:hardcore 参数
grunt buildApp:<AppName>:<SDK> 构建一个用于 iPhone 模拟器的 iOS 应用。 咱们预计这个应用的路径是 sample-code/apps/<AppName>/build/Release-iphonesimulator/<AppName>.app. 默认的 SDK 是 'iphonesimulator7.1'
grunt signApp:<certName> 使用开发证书的绝对路径,签名测试应用。
grunt authorize 受权模拟器,使它不须要弹框请求权限。
grunt log 打印 appium.log (运行测试的时候颇有用)
grunt configAndroidBootstrap 配置使用 ant 构建 Android 的 bootstrap.jar
grunt buildAndroidBootstrap 使用 ant 构建 bootstrap.jar
grunt buildSelendroidServer 构建 selendroid 服务器
grunt configAndroidApp:<AppName> 配置使用 ant 构建 android 测试应用。 咱们期待有一个 sample-code/apps/<AppName> 的 Android 项目
grunt buildAndroidApp:<AppName> 使用 ant 构建项目. 会在 sample-code/apps/<AppName> 下生成应用。
grunt installAndroidApp:<AppName> 将安卓应用安装到模拟器和设备中去
grunt docs 生成文档
grunt generateAppiumIo 将 README.md 转成 appium.io 的 getting-started.html
grunt setConfigVer:<device> 将 package.json 里面 appium 的版本号和对应设备写入 .appiumconfig.json 文件
其余

grunt buildApp 默认使用 iPhone 6.1 模拟器的 SDK 来构建应用。你能够传其余的 SDK 给 grunt 命令。
(用 xcodebuild -showsdks 找出你全部的 sdk):

grunt buildApp:UICatalog:iphonesimulator6.0

4.4 如何去写文档
如何去写文档

## 被用于写第二级标题。每一个文档必须以第二级标题开头。
这是为了支持appium.io文档的生成,不要使用下划线---的方式来建立标题。
不要使用第一级标题或者 === 底线方式来建立标题(其中文件夹名字被用于第一级标题)
小标题

### 用于小标题。
普通标题

#### 用于不会出如今目录中的标题。
不要使用第五级标题 #####, 或者第六级标题 ######。
分隔线

不要使用分隔线例如 -- 或者 ---。 这会使 Slate 混乱。
连接

连接到 readme:

[readme](../../README.md)

连接到 contributing:

[contributing](../../CONTRIBUTING.md)

连接到其余文档:

[link text](filename.md)

连接到文档的内部, 使用 # 来标记 Slate 连接。

[go direct to json](filename.md#json-wire-protocol-server-extensions)

须要注意的是当标题改变时,哈希连接会损坏。因此连接到文档的开头是最好的( other.md 替换 other.md#something )。
appium.io兼容性
在appium.io中心对齐代码

Appium.io中文档使用 slate 来做为文档标准
若是在文件中的代码段不是特定语言或若是你想要代码片断保持与文本中心对齐在 appium.io 文档中,请把代码块放在中心位置
例子:
中心
代码片断放在这里
发布

发布文档请在appium.io中查看 api-docs 和
在 appium.io 中查看。

4.5 代码风格指南
贡献者的代码风格指南

感谢大家对 Appium 的贡献! 这些是咱们书写 javascript 代码时使用的基本原则。
请遵照这些,避免风格的来回修改,以便咱们能够合并你的 pull 请求。
基本原则就是:让你的代码看起来和周围的代码一致。
衍合(Rebasing)

每一个 pull 请求中的提交(commits)必须包括 logical changes。
若是有多个做者,确认每一个做者有本身的提交。最好不要修改做者信息。
合并(merge)提交必须从 pull 请求中 rebase 。
检错(Linting)

全部的代码 (除了 bootstrap.js 的代码,它使用了 Apple 的私有方法) 必须经过 JSLint。
为了检查你的代码,你能够在 Appium 存储目录下,简单地运行 grunt lint。
若是你已建立一个新的 .js 文件,请确认它在 grunt.js 中被通配符覆盖,或者被专门添加。

边输入边检错你的代码是容易实现的,使得整个进程更加顺利。
咱们喜欢 jshint, 由于它有与许多源代码编辑器的集成。
文件 .jshintrc 加入到仓库中,它的内容是:

{
"laxcomma": true,
"strict": true,
"undef": true,
"unused": true,
"trailing": true,
"node": true,
"es5": true,
"white": true,
"indent": 2
}

由于jshint再也不执行代码风格,咱们也使用 jscs,它其中也存在许多源代码编辑器的集成。配置文件是:

{
"excludeFiles": ["submodules/**", "node_modules/**",
"./lib/server/static/**", "./lib/devices/firefoxos/atoms/*.js",
"./test/harmony/**/*.js", "./sample-code/examples/node/**/*-yiewd.js",
"./sample-code/apps/**", "./sample-code/examples/php/vendor/**"],
"requireCurlyBraces": ["for", "while", "do", "try", "catch"],
"requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch",
"return", "try", "catch", "function"],
"disallowMixedSpacesAndTabs": true,
"disallowTrailingWhitespace": true,
"requireSpacesInFunctionExpression": {
"beforeOpeningCurlyBrace": true
}
}

你将在你喜欢的编辑器中看到这些在配置文件中定义的警告类型,查看this page for jshint 和
this page for jscs,编辑器和平台列表,找到使你的编辑器自动化检错的设置方法。
风格注意点

使用两个空格来缩进, 不要使用 tabs

在运算符两边,分别添加一个空格:

var x = 1;

而不是
js
var x=1;

在 lists, objects, function calls 等中,逗号和冒号后面须要添加一个空格:

var x = myFunc("lol", {foo: bar, baz: boo});

而不是
js
var x = myFunc("lol",{foo:bar,baz:boo});

代码语句通常以分号结尾

以逗号开头:

var x = {
foo: 'bar'
, baz: 'boo'
, wuz: 'foz'
};

左花括号应该和 function, if 等 写在同一行, else 被夹在两个花括号中间:

if (foo === bar) {
// do something
} else {
// do something else
}

if, for, 和 function 以后须要添加空格:

if (foo === bar) {

for (var i = 0; i < 10; i ++) {

var lol = function (foo) {

而不是
js
if(foo === bar) {

js
for(var i = 0; i < 10; i ++) {

js
var lol = function(foo) {

只有一行代码时,花括号也应该添加上:

if (foo === bar) {
foo++;
}

而不是
js
if (foo === bar)
foo++;

通常状况下,使用 ===, 而不是 ==; 使用 !==, 而不是 !=

单行长度不该超过79个字符

截断长字符串,方法以下:

myFunc("This is a really long string that's longer " +
"than 79 characters so I broke it up, woo");

注释须要和上一行代码左对齐:

if (foo === 5) {
myFunc(foo);
// foo++;
}

而不是
js
if (foo === 5) {
myFunc(foo);
//foo++;
}

除了出错后直接调用回调函数(callback)处理错误(error)的语句

if (err) return cb(err);

经过拓展原型,来建立子类:

var _ = require('underscore');

var SuperClass = function () {
this.init();
};

SuperClass.prototype.init = function () {
// initialize
};

// Create a subclass

var SubClass = function () {
this.init();
};

_.extend(SubClass.prototype, SuperClass.prototype);

函数定义中,最后使用回调函数:

var foo = function (arg1, arg2, cb) {
...
};

使用变量来定义函数:

var myFunc = function (a, b, c) {};

而不是
js
function myFunc (a, b, c) {}

变量名应该是驼峰式大小写风格:

var myVariable = 42;

而不是
js
var my_variable = 42;

检查是否有未定义的变量:

typeof myVariable === "undefined"

而不是
js
myVariable === undefined

试验风格:

在代码语义通顺和长度许可下,能够保持在同一行:

样例:

driver.elementByTagName('el1').should.become("123")
.nodeify(done);

driver
.elementsByTagName('el1').should.eventually.have.length(0)
.nodeify(done);

或者使用缩进来提升代码的可读性:

h.driver
.elementById('comments')
.clear()
.click()
.keys("hello world")
.getValue()
.should.become("hello world")
.elementById('comments')
.getValue().should.become("hello world")
.nodeify(done);

h.driver
.execute("'nan'--")
.should.be.rejectedWith("status: 13")
.nodeify(done);

第五章:appium使用
5.1 Appium 客户端库
Appium 客户端库

Appium 有对应如下语言的客户端库:
语言 代码
Ruby GitHub
Python GitHub
Java GitHub
JavaScript GitHub
PHP GitHub
C# GitHub
Objective-C GitHub

请注意:有些方法,好比 endTestCoverage() 目前不能提供完整支持。
只有这个问题修复, 完整的覆盖率支持才会被添加。
若是你必定要用这些方法,请先查看 Github 上关于 bindings 的文档。
锁定

锁定屏幕

# ruby
lock 5

# python
driver.lock(5)

// java
driver.lockScreen(3);

// javascript
driver.lock(3)

// php
$this->lock(3);

// c#
driver.LockDevice(3);

// objective c
[driver lockDeviceScreen:3];

将 app 置于后台

把当前应用放到后台去

# ruby
background_app 5

# python
driver.background_app(5)

// java
driver.runAppInBackground(5);

// javascript
driver.backgroundApp(5)

// php
$this->backgroundApp(5);

// c#
driver.BackgroundApp(5);

// objective c
[driver runAppInBackground:3];

收起键盘

收起键盘

# ruby
hide_keyboard

# python
driver.hide_keyboard()

// java
driver.hideKeyboard();

// javascript
driver.hideKeyboard()

// php
$this->hideKeyboard();
$this->hideKeyboard(array('strategy' => 'pressKey', 'key' => 'Done'));

// c#
driver.HideKeyboard("Done");

// objective c
[driver hideKeyboard];

启动 Activity

在当前应用中打开一个 activity 或者启动一个新应用并打开一个 activity 。 只能在 Android 上使用

// java
driver.startActivity("appPackage","com.example.android.apis", null, null);

// javascript
driver.startActivity({appPackage: 'com.example.android.apis', appActivity: '.Foo'}, cb);

# python
driver.start_activity('com.example.android.apis', '.Foo')

# ruby
start_activity app_package: 'io.appium.android.apis', app_activity: '.accessibility.AccessibilityNodeProviderActivity'

// c#
driver.StartActivity("com.example.android.apis", ".Foo");

// php
$this->startActivity(array("appPackage" => "com.example.android.apis",
"appActivity" => ".Foo"));

// objective c
[driver startActivity:@"com.example.android.apis" package:@".Foo"];

打开通知栏 (Notifications)

打开下拉通知栏 只能在 Android 上使用

// java
driver.openNotifications();

// javascript
driver.openNotifications(cb);

# python
driver.open_notifications()

# ruby
openNotifications

// c#
driver.OpenNotifications();

// php
$this->openNotifications();

// objective c
[driver openNotifications];

是否已经安装

检查应用是否已经安装

# ruby
is_installed? "com.example.android.apis"

# python
driver.is_app_installed('com.example.android.apis')

// java
driver.isAppInstalled("com.example.android.apis")

// javascript
driver.isAppInstalled("com.example.android.apis")
.then(function (isAppInstalled) { /*...*/ })

// php
$this->isAppInstalled('com.example.android.apis');

// c#
driver.IsAppInstalled("com.example.android.apis-");

// objective c
[driver isAppInstalled:@"com.example.android.apis-"];

安装应用

安装应用到设备中去

# ruby
install 'path/to/my.apk'

# python
driver.install_app('path/to/my.apk')

// java
driver.installApp("path/to/my.apk")

// javascript
driver.installApp("path/to/my.apk")

// php
$this->installApp('path/to/my.apk');

// c#
driver.InstallApp("path/to/my.apk");

// objective c
[driver installAppAtPath:@"path/to/my.apk"];

删除应用

从设备中删除一个应用

# ruby
remove 'com.example.android.apis'

# python
driver.remove_app('com.example.android.apis')

// java
driver.removeApp("com.example.android.apis")

// javascript
driver.removeApp("com.example.android.apis")

// php
$this->removeApp('com.example.android.apis');

// c#
driver.RemoveApp("com.example.android.apis");

// objective c
[driver removeApp:@"com.example.android.apis"];

摇晃 (Shake)

模拟设备摇晃

# ruby
shake

# python
driver.shake()

// java
driver.shake()

// javascript
driver.shake()

// php
$this->shake();

// c#
driver.ShakeDevice();

// objective c
[driver shakeDevice];

关闭应用

关闭应用

# ruby
close_app

# python
driver.close_app();

// java
driver.closeApp()

// javascript
driver.closeApp()

// php
$this->closeApp();

// c#
driver.CloseApp();

// objective c
[driver closeApp];

启动 (Launch)

根据服务关键字 (desired capabilities) 启动会话 (session) 。请注意这必须在设定 autoLaunch=false 关键字时才能生效。这不是用于启动指定的 app/activities ————你可使用 start_activity 作到这个效果————这是用来继续进行使用了 autoLaunch=false 关键字时的初始化 (Launch) 流程的。

# ruby
launch

# python
driver.launch_app()

// java
driver.launchApp()

// javascript
driver.launchApp()

// php
$this->launchApp();

// c#
driver.LaunchApp();

// objective c
[driver launchApp];

重置 (Reset)

应用重置

(翻译者注:至关于卸载重装应用)

# ruby
reset

# python
driver.reset()

// java
driver.resetApp()

// javascript
driver.resetApp()

// php
$this->reset();

// c#
driver.ResetApp();

// objective c
[driver resetApp];

可用上下文 (context)

列出全部的可用上下文

翻译备注:context能够理解为 可进入的窗口 。例如,对于原生应用,可用的context和默认context均为NATIVE_APP。详情可查看对混合应用进行自动化测试

# ruby
context_array = available_contexts

# python
driver.contexts

// java
driver.getContextHandles()

// javascript
driver.contexts().then(function (contexts) { /*...*/ })

// php
$this->contexts();

// c#
driver.GetContexts()

// objective c
NSArray *contexts = driver.allContexts;

当前上下文 (context)

列出当前上下文

# ruby
context = current_context

# python
driver.current_context

// java
driver.getContext()

// javascript
driver.currentContext().then(function (context) { /*...*/ })

// php
$this->context();

// c#
driver.GetContext()

// objective c
NSString *context = driver.context;

切换到默认的上下文 (context)

将上下文切换到默认上下文

# ruby
switch_to_default_context

# python
driver.switch_to.context(None)

// java
driver.context();

// javascript
driver.context()

// php
$this->context(NULL);

// c#
driver.SetContext();

// objective c
[driver setContext:nil];

应用的字符串 (App Strings)

获取应用的字符串

# ruby
strings = app_strings

# python
driver.app_strings

// java
driver.getAppStrings();

// javascript
driver.getAppStrings().then(function (appStrings) { /*...*/ })

// php
$this->appStrings();
$this->appStrings('ru');

// c#
driver.GetAppStrings();

// objective c
[driver appStrings];
[driver appStringsForLanguage:"@ru"];

按键事件 (Key Event)

给设备发送一个按键事件

# ruby
key_event 176

# python
driver.keyevent(176)

// java
driver.sendKeyEvent(AndroidKeyCode.HOME);

// javascript
driver.deviceKeyEvent(wd.SPECIAL_KEYS.Home)

// php
$this->keyEvent('176');

// c#
driver.KeyEvent("176");

// objective c
NSError *err;
[driver triggerKeyEvent:176 metastate:0 error:&err];

当前 Activity

获取当前 activity。只能在 Android 上使用

# ruby
current_activity

# python
driver.current_activity

// java
driver.currentActivity();

// javascript
driver.getCurrentActivity().then(function (activity) { /*...*/ })

// php
$this->currentActivity();

// c#
driver.GetCurrentActivity();

// objective c
NSError *err;
[driver currentActivity];

触摸动做(TouchAction) / 多点触摸动做(MultiTouchAction)

生成触摸动做的接口。这部分文档很快将会补充更多的内容进来。

# ruby
touch_action = Appium::TouchAction.new
element = find_element :name, 'Buttons, Various uses of UIButton'
touch_action.press(element: element, x: 10, y: 10).perform

# python
action = TouchAction(driver)
action.press(element=el, x=10, y=10).release().perform()

// java
TouchAction action = new TouchAction(driver)
.press(mapview, 10, 10)
.release().
perform();

// javascript
var action = new wd.TouchAction(driver);
action
.tap({el: el, x: 10, y: 10})
.release();
return action.perform(); // returns a promise

// php
$action = $this->initiateTouchAction();
->press(array('element' => $el))
->release()
->perform();

$action1 = $this->initiateTouchAction();
$action1->press(array('element' => $els[0]))
->moveTo(array('x' => 10, 'y' => 0))
->moveTo(array('x' => 10, 'y' => -75))
->moveTo(array('x' => 10, 'y' => -600))
->release();

$action2 = $this->initiateTouchAction();
$action2->press(array('element' => $els[1]))
->moveTo(array('x' => 10, 'y' => 10))
->moveTo(array('x' => 10, 'y' => -300))
->moveTo(array('x' => 10, 'y' => -600))
->release();

$multiAction = $this->initiateMultiAction();
$multiAction->add($action1);
$multiAction->add($action2);
$multiAction->perform();

// c#
ITouchAction action = new TouchAction(driver);
action.Press(el, 10, 10).Release();
action.Perform ();

滑动(Swipe)

模拟用户滑动

# ruby
swipe start_x: 75, start_y: 500, end_x: 75, end_y: 0, duration: 0.8

# python
driver.swipe(start=75, starty=500, endx=75, endy=0, duration=800)

// java
driver.swipe(75, 500, 75, 0, 0.8)

// javascript
function swipe(opts) {
var action = new wd.TouchAction(this);
action
.press({x: opts.startX, y: opts.startY})
.wait(opts.duration)
.moveTo({x: opts.endX, y: opts.endY})
.release();
return action.perform();
}
wd.addPromiseChainMethod('swipe', swipe);
// ...
return driver.swipe({ startX: 75, startY: 500,
endX: 75, endY: 0, duration: 800 });

// php
$this->swipe(75, 500, 75, 0, 800);

// c#
todo: c#

捏 (Pinch)

捏屏幕 (双指往内移动来缩小屏幕)

# ruby
pinch 75

# python
driver.pinch(element=el)

// java
driver.pinch(element);

// javascript
function pinch(el) {
return Q.all([
el.getSize(),
el.getLocation(),
]).then(function(res) {
var size = res[0];
var loc = res[1];
var center = {
x: loc.x + size.width / 2,
y: loc.y + size.height / 2
};
var a1 = new wd.TouchAction(this);
a1.press({el: el, x: center.x, y:center.y - 100}).moveTo({el: el}).release();
var a2 = new wd.TouchAction(this);
a2.press({el: el, x: center.x, y: center.y + 100}).moveTo({el: el}).release();
var m = new wd.MultiAction(this);
m.add(a1, a2);
return m.perform();
}.bind(this));
};
wd.addPromiseChainMethod('pinch', pinch);
wd.addElementPromiseChainMethod('pinch', function() {
return this.browser.pinch(this);
});
// ...
return driver.pinch(el);
// ...
return el.pinch();

$this->pinch($el);

// c#
driver.Pinch(25, 25)

放大 (Zoom)

放大屏幕 (双指往外移动来放大屏幕)

# ruby
zoom 200

# python
driver.zoom(element=el)

// java
driver.zoom(element);

// javascript
function zoom(el) {
return Q.all([
this.getWindowSize(),
this.getLocation(el),
]).then(function(res) {
var size = res[0];
var loc = res[1];
var center = {
x: loc.x + size.width / 2,
y: loc.y + size.height / 2
};
var a1 = new wd.TouchAction(this);
a1.press({el: el}).moveTo({el: el, x: center.x, y: center.y - 100}).release();
var a2 = new wd.TouchAction(this);
a2.press({el: el}).moveTo({el: el, x: center.x, y: center.y + 100}).release();
var m = new wd.MultiAction(this);
m.add(a1, a2);
return m.perform();
}.bind(this));
};
wd.addPromiseChainMethod('zoom', zoom);
wd.addElementPromiseChainMethod('zoom', function() {
return this.browser.zoom(this);
});
// ...
return driver.zoom(el);
// ...
return el.zoom();

// php
$this->zoom($el);

// c#
driver.Zoom(100, 200);

滑动到 (Scroll To)

滑动到某个元素。

# ruby
element = find_element :name, 'Element Name'
execute_script "mobile: scrollTo", :element => element.ref

# python
todo: python

// java
WebElement element = driver.findElement(By.name("Element Name"));
HashMap<String, String> arguments = new HashMap<String, String>();
arguments.put("element", element.getId());
(JavascriptExecutor)driver.executeScript("mobile: scrollTo", arguments);

// javascript
return driver.elementByName().then(function (el) {
return driver.execute('mobile: scrollTo', {element: el.value});
});

// php
$els = $this->elements($this->using('class name')->value('android.widget.TextView'));
$this->scroll($els[count($els) - 1], $els[0]);

// c#
todo: csharp

拉出文件 (Pull File)

从设备中拉出文件

# ruby
pull_file 'Library/AddressBook/AddressBook.sqlitedb'

# python
driver.pull_file('Library/AddressBook/AddressBook.sqlitedb')

// java
driver.pullFile("Library/AddressBook/AddressBook.sqlitedb");

// javascript
driver.pullFile("Library/AddressBook/AddressBook.sqlitedb")
.then(function (base64File) { /*...*/ })

// php
$this->pullFile('Library/AddressBook/AddressBook.sqlitedb');

// c#
driver.PullFile("Library/AddressBook/AddressBook.sqlitedb");

推送文件(Push file)

推送文件到设备中去

# ruby
data = "some data for the file"
path = "/data/local/tmp/file.txt"
push_file path, data

# python
data = "some data for the file"
path = "/data/local/tmp/file.txt"
driver.push_file(path, data.encode('base64'))

// java
byte[] data = Base64.encodeBase64("some data for the file".getBytes());
String path = "/data/local/tmp/file.txt";
driver.pushFile(path, data)

// javascript
driver.pushFile(path, data)

// php
$path = 'data/local/tmp/test_push_file.txt';
$data = 'This is the contents of the file to push to the device.';
$this->pushFile($path, base64_encode($data));

// c#
driver.PushFile("/data/local/tmp/file.txt", "some data for the file");

设置

从这里你能够获取/设置 appium 的服务器设置。
想知道它如何工做,以及它支持哪些设置,请查看关于设置的文档

current_settings = get_settings
update_settings someSetting: true

current_settings = driver.get_settings()
driver.update_settings({"someSetting": true})

JsonObject settings = driver.getSettings()
// java-client doesn't support setting arbitrary settings, just settings which are already provided by appium.
// So for the 'ignoreUnimportantViews' setting, the following method exists:
driver.ignoreUnimportantViews(true);

var settings = driver.settings();
browser.updateSettings({'someSetting': true});

$settings = $this->getSettings();
$this->updateSettings(array('cyberdelia' => "open"));

Dictionary<String, Object>settings = driver.GetSettings();
// dotnet-driver doesn't support setting arbitrary settings, just settings which are already provided by appium.
// So for the 'ignoreUnimportantViews' setting, the following method exists:
driver.IgnoreUnimportantViews(true);

Appium 桌面应用

Appium 的桌面应用支持 OS X 和 Windows.

Appium.app for OS X
Appium.exe for Windows

5.2 Appium 服务关键字
Appium 服务关键字

<expand_table>
关键字 描述 实例
automationName 你想使用的自动化测试引擎 Appium (默认) 或 Selendroid
platformName 你要测试的手机操做系统 iOS, Android, 或 FirefoxOS
platformVersion 手机操做系统版本 例如: 7.1, 4.4
deviceName 使用的手机类型或模拟器类型 iPhone Simulator, iPad Simulator, iPhone Retina 4-inch, Android Emulator, Galaxy S4, 等。在 iOS 上,这个关键字的值必须是使用 instruments -s devices 获得的可以使用的设备名称之一。在 Android 上,这个关键字目前不起做用。
app .ipa or .apk文件所在的本地绝对路径或者远程路径,也能够是一个包括二者之一的.zip。 Appium会先尝试安装路径对应的应用在适当的真机或模拟器上。针对Android系统,若是你指定app-package和app-activity(具体见下面)的话,那么就能够不指定app。 会与 browserName 冲突 好比/abs/path/to/my.apk或http://myapp.com/app.ipa
browserName 须要进行自动化测试的手机 web 浏览器名称。若是是对应用进行自动化测试,这个关键字的值应为空。 iOS 系统上能够用 'Safari' ,Android 系统上能够用 'Chrome', 'Chromium', 或 'Browser'。
newCommandTimeout 设置命令超时时间,单位:秒。达到超时时间仍未接收到新的命令时 Appium 会假设客户端退出而后自动结束会话。 好比 60
autoLaunch Appium是否须要自动安装和启动应用。默认值true true, false
language (Sim/Emu-only) 设定模拟器 ( simulator / emulator ) 的语言。 如: fr
locale (Sim/Emu-only) 设定模拟器 ( simulator / emulator ) 的区域设置。 如: fr_CA
udid 链接的物理设备的惟一设备标识 如: 1ae203187fc012g
orientation (Sim/Emu-only) 在一个设定的方向模式中开始测试 LANDSCAPE (横向) 或 PORTRAIT (纵向)
autoWebview 直接转换到 WebView 上下文。 默认值 false、 true, false
noReset 不要在会话前重置应用状态。默认值false。 true, false
fullReset (iOS) 删除整个模拟器目录。(Android) 经过卸载——而不是清空数据——来重置应用状态。在 Android 上,这也会在会话结束后自动清除被测应用。默认值 false true, false
Android特有

<expand_table>
关键字 描述 实例
appActivity 你要从你的应用包中启动的 Android Activity 名称。它一般须要在前面添加 . (如:使用.MainActivity 而不是 MainActivity) MainActivity, .Settings
appPackage 你想运行的Android应用的包名 好比com.example.android.myApp, com.android.settings
appWaitActivity 你想要等待启动的 Android Activity 名称 SplashActivity
deviceReadyTimeout 设置等待一个模拟器或真机准备就绪的超时时间 5
androidCoverage 用于执行测试的 instrumentation 类。做为命令 adb shell am instrument -e coverage true -w 的 -w 参数。 com.my.Pkg/com.my.Pkg.instrumentation.MyInstrumentation
enablePerformanceLogging (仅适用于 Chrome 和 webview) 开启 Chromedriver 的性能日志。 (默认 false) true, false
androidDeviceReadyTimeout 等待设备在启动应用后准备就绪的超时时间。以秒为单位。 如 30
androidDeviceSocket 开发工具的 socket 名称。只有在被测应用是一个使用 Chromium 内核的浏览器时须要。 socket 会被浏览器打开,而后 Chromedriver 把它做为开发者工具来进行链接。 如 chrome_devtools_remote
avd 须要启动的 AVD (安卓虚拟设备) 名称。 如 api19
avdLaunchTimeout 以毫秒为单位,等待 AVD 启动并链接到 ADB 的超时时间。(默认值 120000) 300000
avdReadyTimeout 以毫秒为单位,等待 AVD 完成启动动画的超时时间。(默认值 120000) 300000
avdArgs 启动 AVD 时须要加入的额外的参数。 如 -netfast
useKeystore 使用一个自定义的 keystore 来对 apk 进行重签名。默认值 false true or false
keystorePath 自定义 keystore 的路径。默认: ~/.android/debug.keystore 如 /path/to.keystore
keystorePassword 自定义 keystore 的密码。 如 foo
keyAlias key 的别名 如 androiddebugkey
keyPassword key 的密码 如 foo
chromedriverExecutable webdriver 可执行文件的绝对路径 (若是 Chromium 核心提供了对应的 webdriver, 应该用它代替 Appium 自带的 webdriver) /abs/path/to/webdriver
autoWebviewTimeout 以毫秒为单位,等待 Webview 上下文激活的时间。默认值 2000 如 4
intentAction 用于启动 activity 的 intent action。 (默认值 android.intent.action.MAIN) 如 android.intent.action.MAIN, android.intent.action.VIEW
intentCategory 用于启动 activity 的 intent category。 (默认值 android.intent.category.LAUNCHER) 如 android.intent.category.LAUNCHER, android.intent.category.APP_CONTACTS
intentFlags 用于启动 activity 的标识 ( flags ) (默认值 0x10200000) 如 0x10200000
optionalIntentArguments 用于启动 activity 的额外 intent 参数。请查看 Intent 参数 如 --esn <EXTRA_KEY>, --ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE>
stopAppOnReset 在使用 adb 启动应用前中止被测应用的进程 ( process ) 。若是被测应用是被另外一个应用建立的,当这个参数被设定为 false 时,容许另外一个应用的进程在使用 adb 启动被测应用时继续存活。默认值 true true 或 false
unicodeKeyboard 使用 Unicode 输入法。默认值 false true 或 false
resetKeyboard 在设定了 unicodeKeyboard 关键字的 Unicode 测试结束后,重置输入法到原有状态。若是单独使用,将会被忽略。默认值 false true 或 false
noSign 跳过检查和对应用进行 debug 签名的步骤。只能在使用 UiAutomator 时使用,使用 selendroid 是不行。默认值 false true 或 false
ignoreUnimportantViews 调用 uiautomator 的函数 setCompressedLayoutHierarchy()。因为 Accessibility 命令在忽略部分元素的状况下执行速度会加快,这个关键字能加快测试执行的速度。被忽略的元素将不可以被找到,所以这个关键字同时也被实现成能够随时改变的 *设置 ( settings ) * 。默认值 false true 或 false
iOS特有

<expand_table>
关键字 描述 实例
calendarFormat (Sim-only) 为iOS的模拟器设置日历格式 如 gregorian (公历)
bundleId 被测应用的 bundle ID 。用于在真实设备中启动测试,也用于使用其余须要 bundle ID 的关键字启动测试。在使用 bundle ID 在真实设备上执行测试时,你能够不提供 app 关键字,但你必须提供 udid 。 如 io.appium.TestApp
udid 链接的真实设备的惟一设备编号 ( Unique device identifier ) 如 1ae203187fc012g
launchTimeout 以毫秒为单位,在 Appium 运行失败以前设置一个等待 instruments 的时间 好比: 20000
locationServicesEnabled (Sim-only) 强制打开或关闭定位服务。默认值是保持当前模拟器的设定 true 或 false
locationServicesAuthorized (Sim-only) 经过修改 plist 文件设定是否容许应用使用定位服务,从而避免定位服务的警告出现。默认值是保持当前模拟器的设定。请注意在使用这个关键字时,你同时须要使用 bundleId 关键字来发送你的应用的 bundle ID。 true 或者 false
autoAcceptAlerts 当 iOS 的我的信息访问警告 (如 位置、联系人、图片) 出现时,自动选择接受( Accept )。默认值 false。 true 或者 false
autoDismissAlerts 当 iOS 的我的信息访问警告 (如 位置、联系人、图片) 出现时,自动选择不接受( Dismiss )。默认值 false。 true 或者 false
nativeInstrumentsLib 使用原生 intruments 库 (即关闭 instruments-without-delay ) true 或者 false
nativeWebTap (Sim-only) 在Safari中容许"真实的",非基于 javascript 的 web 点击 (tap) 。 默认值: false。注意:取决于 viewport 大小/比例, 点击操做不必定能精确地点中对应的元素。 true 或者 false
safariInitialUrl (Sim-only) (>= 8.1) 初始化 safari 的时使用的地址。默认是一个本地的欢迎页面 如 https://www.github.com
safariAllowPopups (Sim-only) 容许 javascript 在 Safari 中建立新窗口。默认保持模拟器当前设置。 true 或者 false
safariIgnoreFraudWarning (Sim-only) 阻止 Safari 显示此网站可能存在风险的警告。默认保持浏览器当前设置。 true 或者 false
safariOpenLinksInBackground (Sim-only) Safari 是否容许连接在新窗口打开。默认保持浏览器当前设置。 true 或者 false
keepKeyChains (Sim-only) 当 Appium 会话开始/结束时是否保留存放密码存放记录 (keychains) (库(Library)/钥匙串(Keychains)) true 或者 false
localizableStringsDir 从哪里查找本地化字符串。默认值 en.lproj en.lproj
processArguments 经过 instruments 传递到 AUT 的参数 如 -myflag
interKeyDelay 以毫秒为单位,按下每个按键之间的延迟时间。 如 100
showIOSLog 是否在 Appium 的日志中显示设备的日志。默认值 false true 或者 false
sendKeyStrategy 输入文字到文字框的策略。模拟器默认值:oneByOne (一个接着一个) 。真实设备默认值:grouped (分组输入) oneByOne, grouped 或 setValue
screenshotWaitTimeout 以秒为单位,生成屏幕截图的最长等待时间。默认值: 10。 如 5
waitForAppScript 用于判断 "应用是否被启动” 的 iOS 自动化脚本代码。默认状况下系统等待直到页面内容非空。结果必须是布尔类型。 例如 true;, target.elements().length > 0;, $.delay(5000); true;

5.3 元素定位
元素定位与交互

Appium支持webdriver定位策略的子集

根据"class"定位(例如, UI组件类型)
根据"xpath"定位 (例如,具备必定约束的路径抽象标示, 基于XPath方式)

另外, Appium 还支持部分 Mobile JSON 链接协议 的定位策略

ios uiautomation: 一个递归地、对应使用 UIAutomation library 搜索元素的字符串(iOS-only)
android uiautomator: 一个递归地、对应使用 UiAutomator Api搜索元素的字符串 (Android-only)
accessibility id: 一个递归地、使用本地Accessibility选项实现的Id/Name进行元素搜索的字符串。

存在的问题

若是遇到定位元素变得无效请联系并告知咱们。咱们将会努力修复
使用Appium Inspector来定位元素

(翻译备注: 这个工具目前只有Mac版本, 若是你使用的是windows, 可使用android sdk自带的 uiautomatorviewer 工具来得到元素的位置)

Appium提供了一个灵活的工具Appium Inspector, 容许你在app运行的时候, 直接定位你正在关注的元素. 经过Appium Inspector(靠近start test按钮的小"i"按钮), 你能够经过点击预览窗口上的控件来得到它的name属性, 或者直接在UI导航窗口中定位
概述

Appium Inspector有一个简单的布局, 所有由以下窗口组成.
UI导航器, 预览, 录制与刷新按钮, 和交互工具

Step 1
例子

启动Appium Inspector后(经过点击app右上的小"i"按钮), 你能够定位任何预览窗口中的元素. 做为测试, 我正在查找id为"show alert"的按钮

Step 1

要找到这个按钮的id, 在定位预览窗口中我点击了"show alert"按钮, Appium Inspector在UI导航窗口中高亮显示了这个元素, 而后展现了刚被点击按钮的id和元素类型

Step 1

5.4 IOS谓词
iOS 谓词(Predicate)

在查看 '-ios uiautomation' 搜索策略时了解 谓词(Predicate) 十分必要。 UIAutomation JavaScript API有下列几种很是有用的方法:

(UIAElement) UIAElementArray.firstWithPredicate(PredicateString predicateString)
(UIAElementArray) UIAElementArray.withPredicate(PredicateString predicateString)

原生的JS搜索策略(由Apple提供)提供了更大的灵活性,而且和XPath很像。
谓词(Predicate) 能够经过使用多个匹配条件来准肯定位某一个或某一组元素(至关于只有搜索条件与元素的计算结果为 true 时这些元素才会被认为是匹配的)。

(翻译备注:XPath 是一门用来定位 xml 文档中的元素的语言,能提供基于路径、元素属性等条件的定位策略)

例如:

// java
appiumDriver.findElementsByIosUIAutomation("collectionViews()[0].cells().withPredicate(\"ANY staticTexts.isVisible == TRUE\")")

- 将只选择那些在主视图第一个 UIACollectionView 元素下的、拥有可见子元素 UIAStaticText 的 UIACollectionCell 元素。在这里, staticTexts() 和 isVisible() 分别是UIAElementArray 和 UIAElement 的子方法。 注意: UIAElementArray 序列编号从 0 开始,而不是像 Xpath 那样从 1开始

如下是全部可用的谓词(Predicate)的列表(主要取自 谓词(Predicate) 编程指南)
基本比较

= , ==
- 左边表达式等于右边表达式:

tableViews()[1].cells().firstWithPredicate("label == 'Olivia' ")

same in Xpath: /UIATableView[2]/UIATableCell[@label = 'Olivia'][1]

>= , =>
- 左边表达式大于或等于右边表达式。

<= , =<
- 左边表达式小于或等于右边表达式。

>
- 左边表达式大于右边表达式。

<
- 左边表达式小于右边表达式。

!= , <>
- 左边表达式不等于右边表达式。

BETWEEN
- 左边表达式的值在右边表达式的两个边界值之间或等于其中一个边界值。右边表达式为一个有两个值的数组,数组的第一个值是上限,第二个值是下限(这个顺序是固定的) ,例如 1 BETWEEN { 0 , 33 }, 或者 $INPUT BETWEEN { $LOWER, $UPPER }。
在 Objective-C, 你能够建立一个自定义的 BETWEEN 谓词(Predicate),以下面的示例所示:

NSPredicate *betweenPredicate =
[NSPredicate predicateWithFormat: @"attributeName BETWEEN %@", @[@1, @10]];

这建立了一个等价于 ( ( 1 <= attributeValue ) && ( attributeValue <= 10 ) ) 的谓词
布尔值谓词

TRUEPREDICATE
- 计算结果恒等于 TRUE 。

FALSEPREDICATE
- 计算结果恒等于 FALSE。
基本的复合谓词

AND , &&
- 逻辑与。

OR , ||
- 逻辑或。

NOT , !
- 逻辑非。
字符串比较

在默认状况下,字符串比较是区分大小写和音调( diacritic )的,你能够在方括号中用关键字符 c 和 d 来修改操做符以相应的指定不区分大小写和变音符号。例如 名字的开头 firstName BEGINSWITH[cd] $FIRST_NAME

(翻译备注:这里的音调是指英文字母的音调,如 "náive" 和 "naive"。若是不加关键字 d,这两个字符串会认为是不等价的。)

BEGINSWITH
- 左边的表达式以右边的表达式做为开始。

scrollViews()[3].buttons().firstWithPredicate("name BEGINSWITH 'results toggle' ")

same in Xpath: /UIAScrollView[4]/UIAButton[starts-with(@name, 'results toggle')][1]

CONTAINS
- 左边的表达式包含右边的表达式。

tableViews()[1].cells().withPredicate("ANY collectionViews[0].buttons.name CONTAINS 'opera'")

same in Xpath: /UIATableView[2]/UIATableCell[UIACollectionView[1]/UIAButton[contains(@name, 'opera')]]

ENDSWITH
- 左边的表达式以右边的表达式做为结束。

LIKE
- 左边表达式等于右边表达式: ? 和 *可做为通配符, 其中 ? 匹配 1 个字符, * 匹配 0 个或者多个字符。 在 Mac OS X v10.4, 通配符不能匹配换行符。

tableViews()[0].cells().firstWithPredicate("name LIKE '*Total: $*' ")

same in Xpath: /UIATableView[1]/UIATableCell[matches(@name, '.*Total: \$.*')][1]

MATCHES
- 左边表达式根据ICU v3的正则表达式风格比较,等于右边表达式 (详情请看ICU用户指南中的 正则表达式)。

tableViews().firstWithPredicate("value MATCHES '.*of 7' ")

same in Xpath: /UIATableView[matches(@value, '.*of 7')][1]

聚合操做

ANY , SOME
- 指定匹配后续表达式的任意元素。例如 ANY children.age < 18 。

tableViews()[0].cells().firstWithPredicate("SOME staticTexts.name = 'red'").staticTexts().withName('red')

same in Xpath: /UIATableView[1]/UIATableCell[UIAStaticText/@name = 'red'][1]/UIAStaticText[@name = 'red']

ALL
- 指定匹配后续表达式的全部元素。例如 ALL children.age < 18 。

NONE
- 指定不匹配后续表达式的元素。例如 NONE children.age < 18 。 逻辑上等价于 NOT (ANY ...) 。

IN
- 等价于 SQL 的 IN 操做,左边的表达必须出如今右边指定的集合中。例如 name IN { 'Ben', 'Melissa', 'Matthew' } 。 这个集合能够是一个数组( array ),一个列表( set ), 或者一个字典( dictionary )。当这个集合是字典时,这里使用的是它的值( value )。

array[index]
- 指定数组中特定索引处的元素。

array[FIRST]
- 指定数组中的第一个元素。

array[LAST]
- 指定数组中的最后一个元素。

array[SIZE]
- 指定数组的大小

elements()[0].tableViews()[0].cells().withPredicate("staticTexts[SIZE] > 2")

same in Xpath: /*[1]/UIATableView[1]/UIATableCell[count(UIAStaticText) > 2]

标识符

C语言标识符
- 任何C语言的标识符都不是保留字。

#symbol
- 用来把一个保留字转义为用户标识符。

[\]{octaldigit}{3}
- 用来表示一个八进制数 ( \后面加上3位八进制数字)。

[\][xX]{hexdigit}{2}
- 用于表示十六进制数 ( \x 或 \X 后面加上2个十六进制数字)。

[\][uU]{hexdigit}{4}
- 用于表示 Unicode 编码 ( \u 或 \U 后面加上4个十六进制数字)。
文字 (Literals)

(翻译备注:Literals 在编程语言领域的意思是在代码中能够看获得的(或说可视的)那些值。例如字符串 "a",数组 [1, 2],你能够在代码中一眼看出这是一个字符串,数组仍是别的数据类型并知道它的值。这一节说的就是这些值的写法)

单引号和双引号都能产生相同的结果,但他们不会匹配对方(单引号不会匹配双引号)。例如:"abc" and 'abc' 都是可识别的 ,可是 "a'b'c" 等价于a, 'b', c。

FALSE , NO
- 表示逻辑上的 false。

TRUE , YES
- 表示逻辑上的 true。

NULL , NIL
- 空值。

SELF
- 表明被使用的对象自己。

"text"
- 一个字符串。

'text'
- 同上,也是一个字符串。

以逗号分隔的文本数组
- 举个例子 { 'comma', 'separated', 'literal', 'array' } 。

标准的整数和小数
- 举个例子 1 , 27 , 2.71828 , 19.75 。

带有幂指数的小数
- 举个例子 9.2e-5 。

0x
- 十六进制数的前缀, 如0x11表示十六进制数11,等同于十进制的17。

0o
- 八进制数的前缀。

0b
- 二进制数的前缀。
保留字

下面的都是保留字:

AND, OR, IN, NOT, ALL, ANY, SOME, NONE, LIKE, CASEINSENSITIVE, CI, MATCHES, CONTAINS, BEGINSWITH, ENDSWITH, BETWEEN, NULL, NIL, SELF, TRUE, YES, FALSE, NO, FIRST, LAST, SIZE, ANYKEY, SUBQUERY, CAST, TRUEPREDICATE, FALSEPREDICATE
Appium 谓词(predicate)帮助文档

Appium 在app.js中有 专门的谓词(predicate)使用帮助文档 :

getFirstWithPredicate
getFirstWithPredicateWeighted
getAllWithPredicate
getNameContains

以下是个Ruby的例子

# Ruby example
text = 'Various uses'
predicate = "name contains[c] '#{text}' || label contains[c] '#{text}' || value contains[c] '#{text}'"
element = execute_script(%Q(au.mainApp().getFirstWithPredicate("#{predicate}");))

puts element.name # Buttons, Various uses of UIButton

5.5自动化手机网页应用
自动化手机网页应用

若是你正对于如何在iOS的Safari或Android上的Chrome作网页应用的自动化感兴趣,
那么Appium可以帮助你。基本上,你能够正常的写webdriver测试,只须要把Appium当
成一个有特殊设置的selenium Server。
iOS模拟器上的Safari浏览器

首先,要确保你的Safari浏览器参数中开启了开发者模式,这样Safari的远程调试端口也会被同时打开。

无论你使用模拟器仍是真机,你必须使用Appium开始以前先开启Safari。

而后设置以下显示的这些信息以便于在设备中的Safari执行测试:
``
javascript
// javascript
{
platformName: 'iOS'
, platformVersion: '7.1'
, browserName: 'Safari'
, deviceName: 'iPhone Simulator'
}

 

```python
# python
{
'platformName': 'iOS',
'platformVersion': '7.1',
'browserName': 'Safari',
'deviceName': 'iPhone Simulator'
}

// php
public static $browsers = array(
array(
'desiredCapabilities' => array(
'platformName' => 'iOS',
'platformVersion' => '7.1',
'browserName' => 'Safari',
'deviceName' => 'iPhone Simulator'
)
)
);

// java
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "iOS");
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1");
capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "Safari");
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator");

iOS真机上的Safari浏览器

为了可以在真机上的Safari执行测试,咱们使用了SafariLauncher App来启动Safari。
一旦Safari被启动,则使用ios-webkit-webkit-proxy来自动启动Safari的远程调试功能。

提示: 目前在ios-webkit-debug-proxy中有一个问题。
你必须添加信任才能开始运行ios-webkit-debug-proxy。
前期设置

当你要在真机上的Safari中执行你的测试脚本以前你须要先注意如下几点:

安装并运行 ios-webkit-debug-proxy,并监听27753端口 (具体能够参考(hybrid docs)
打开iOS真机中的 web inspector,能够在iOS6.0或更高版本中的 设置 > safari > 高级找到。
建立一个 provisioning profile 可以帮助你配置safariLauncher。

你能够前往 Apple Developers Member Center 建立一个launcher profile:
* 第一步: 建立一个 新的App Id 同时设置WildCard App ID这个选项置为""
* *第二步:** 为步骤1的App Id建立一个 new Development Profile 。
* 第三步: 选择你的 certificate(s) and device(s) 并选择下一步。
* 第四步: 设置profile的名称以及 generate the profile。
* 第五步: 下载profile并使用文本编辑器打开。
* 第六步: 寻找并牢记你的 UUID

如今你有了本身的profile文件,能够在终端中输入以下的命令:

$ git clone https://github.com/appium/appium.git
$ cd appium

# 选项1:你能够不设置任何的参数。appium会把签名 (code signing identity) 设为'iPhone Developer'
$ ./reset.sh --ios --real-safari

# 选项2:你须要定义code signing identity而且容许xcode选择profile identity code
$ ./reset.sh --ios --real-safari --code-sign '<code signing idendity>'

# 选项3:你须要设置<code signing idendity>和<profile identity code>
$ ./reset.sh --ios --real-safari --code-sign '<code signing idendity>' --profile '<retrieved profile identity code>'

# 设置成功以后,就能够像往常同样启动服务
$ node /lib/server/main.js -U <UDID>

执行测试

若是要在safari下的运行你的测试, 只须要简单的配置"browserName"为safari便可
Java 范例

// java
// 配置web driver并启动webview应用
DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
desiredCapabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "Safari");
URL url = new URL("http://127.0.0.1:4723/wd/hub");
AppiumDriver driver = new AppiumDriver(url, desiredCapabilities);

// 跳转到指定页面并在该页面因此用元素id进行交互
driver.get("http://saucelabs.com/test/guinea-pig");
WebElement div = driver.findElement(By.id("i_am_an_id"));
Assert.assertEquals("I am a div", div.getText()); //跳转到指定页面并在该页面因此用元素id进行交互
driver.findElement(By.id("comments")).sendKeys("My comment"); //经过id查找评论框并输入

// 关闭应用
driver.quit();

Python 范例

# python
# 配置web driver并启动webview应用
capabilities = { 'browserName': 'Safari' }
driver = webdriver.Remote('http://localhost:4723/wd/hub', capabilities)

# 跳转到指定页面并在该页面因此用元素id进行交互
driver.get('http://saucelabs.com/test/guinea-pig');
div = driver.find_element_by_id('i_am_an_id')
# 检查文本是否符合预期
assertEqual('I am a div', div.text)

# 经过id查找评论框并输入
driver.find_element_by_id('comments').send_keys('My comment')

# 关闭应用
driver.quit()

// php
class ContextTests extends PHPUnit_Extensions_AppiumTestCase
{
public static $browsers = array(
array(
'desiredCapabilities' => array(
'platformName' => 'iOS',
'platformVersion' => '7.1',
'browserName' => 'Safari',
'deviceName' => 'iPhone Simulator'
)
)
);

public function testThings()
{
$this->get('http://saucelabs.com/test/guinea-pig');

$div = $this->byId('i_am_an_id');
$this->assertEquals('I am a div', $div->text());

$this->byId('comments')->sendKeys('My comment');
}
}

在真机或模拟器上的Chrome执行测试

须要作的准备:

确认Chrome已经安装在了你的真机或模拟器上 (应用的包名是com.android.chrome) 。在不编译Chromium的状况下, 不可能获得模拟器上的x86版本的chrome,你能够运行一个ARM的模拟器而后从真机上获取一个Chrome的APK安装在模拟器上。
若是你是使用NPM下载的, 或者是在.app运行的话,那你不须要其余额外的工做。若是你是使用源码运行,reset会下载ChromeDriver并放在build。 使用 --chromedriver-version 选项能够指定chromedriver的版本 (例如 ./reset.sh --android --chromedriver-version 2.8), 不然使用最新版。

接着,像这样设置就能够在Chrome上执行测试了:

// javascript
{
platformName: 'Android'
, platformVersion: '4.4'
, deviceName: 'Android Emulator'
, browserName: 'Chrome'
};

# python
{
'platformName': 'Android',
'platformVersion': '4.4',
'deviceName': 'Android Emulator',
'browserName': 'Chrome'
}

// php
public static $browsers = array(
array(
'desiredCapabilities' => array(
'platformName' => 'Android',
'platformVersion' => '4.4',
'browserName' => 'Chrome',
'deviceName' => 'Android Emulator'
)
)
);

// java
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "4.4");
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "Chrome");

在4.4以上的版本,你也能够用'Browser' browserName 来对内置浏览器进行自动化。
在全部版本你均可以用'Chromium' browserName来对Chromium进行自动化。
chromedriver故障排查

从Chrome 33开始,再也不必须将设备root。在以前的版本,设备必须按要求进行root (ChromeDriver须要写 /data/local 目录来设定Chrome的命令行参数) 。

若是在版本33以前在Chrome上测试app,确保adb shell拥有设备中/data/local目录的读写权限:

$ adb shell su -c chmod 777 /data/local

更多关于chromedriver的文档详见ChromeDriver documentation。

5.6 调整网络设置
调整网络设置

Selenium 的 Mobile JSON Wire Protocol Specification 支持一个获取和设置设备网络链接的 API 。这个 API 经过位掩码(bitmask)工做,把全部可能的状态用一个整型数据表示:
值 (别名) 数据链接 Wifi 链接 飞行模式
0 (什么都没有) 0 0 0
1 (飞行模式) 0 0 1
2 (只有Wifi) 0 1 0
4 (只有数据链接) 1 0 0
6 (开启全部网络) 1 1 0

翻译备注:数据连接即2g, 3g, 4g的网络链接。
iOS

很不幸,目前 Appium 在 iOS 下不支持 Selenium 的网络链接 API。
Android

选择你想使用的设置,而后根据上面的表格发送正确的位掩码(bitmask)。

// javascript
// 设置网络链接为飞行模式
driver.setNetworkConnection(1)

// 设置网络链接为仅启用Wifi
driver.setNetworkConnection(2)

// 设置网络链接为仅启用数据链接
driver.setNetworkConnection(4)

// 设置网络链接为启用数据链接和Wifi
driver.setNetworkConnection(6)

获取网络链接设置会返回基于一样规则的位掩码,你能够将其解码来得到网络设置。

// javascript
driver.getNetworkConnection().then(function (connectionType) {
switch (connectionType) {
case 0:
// 无网络
break;
case 1:
// 飞行模式
break;
case 2:
// wifi
break;
case 4:
// 数据链接
break;
case 6:
// wifi和数据链接
break;
}
});

5.7 执行测试
执行测试
准备被测应用 (iOS)

在模拟器上测试apps必需要用模拟器专用的编译器,例如使用下列的命令来编译Xcode项目:

> xcodebuild -sdk iphonesimulator6.0

这行指令在Xcode项目底下建立了一个build/Release-iphonesimulator目录,而且生成一个能够透过Appium服务器来通信的的.app封包。

若是须要,你能够把.app 目录压缩成一个zip压缩档! Appium 会自行解压缩。让你能方便在非本地运行Appium。
准备被测应用 (Android)

用Appium去执行你的.apk档其实没什么特别须要注意的事项。若是须要,你能够把它压缩成zip压缩档。
用Appium测试你的app (iOS)

想知道如何编写测试脚本,请参照测试范例:

Node.js | Python | PHP | Ruby | Java

基本上来讲,首先先肯定你启动了Appium:

node .

而后执行你的WebDriver测试脚本,脚本必须包含下列的环境参数:

// javascript
{
platformName: 'iOS',
platformVersion: '7.1',
deviceName: 'iPhone Simulator',
app: myApp
}

# python
{
'platformName': 'iOS',
'platformVersion': '7.1',
'deviceName': 'iPhone Simulator',
'app': myApp
}

// php
public static $browsers = array(
array(
'desiredCapabilities' => array(
'platformName' => 'iOS',
'platformVersion' => '7.1',
'deviceName' => 'iPhone Simulator',
'app' => $myApp
)
)
);

// java
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "iOS");
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1");
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator");
capabilities.setCapability(MobileCapabilityType.APP, myApp);

在这个脚本集里,myApp必须是下列其中之一:

一个模拟器编译过的.app 目录或者.zip 文件的本地绝对路径
一个包含着你的.app封包的zip档的url
appium安装根目录下的一个示例app的相对路径

在你选择的WebDriver库里,设定remote session使用上述的环境参数而后使用端口4723来链接本地服务器(或者使用你在Appium启动时所设定的端口)。如今你已经完成设置了!
用Appium测试你的app (Android)

首先,先肯定你有一个并且必须是只能一个Android模拟器或者设备链接着。若是你输入adb devices,你应该只看到一个设备链接着。这将是Appium所用来测试的设备。固然,要链接一个设备,你须要准备好一个Android AVD (参考(Windows,Mac,或者Linux)以了解更多)。 若是Android SDK工具在你的环境变量path下,你能够简单的执行:

emulator -avd <个人Avd名称>

而后等android模拟器启动。有时候,由于某些缘由,adb会卡住。若是它没有显示任何的设备或其余故障,你可使用下列指令来重启:

adb kill-server && adb devices

如今,确认Appium已经启动:

node .

有几种方法来启动一个Appium程序(效果和经过adb启动如出一辙):

只有apk或者zip,默认activity将会被启动。 (只设置了'app'环境参数)
apk + activity ('app' + 'appActivity' 环境参数)
apk + activity + intent ('app' + 'appActivity' + 'appIntent' 环境参数)
...

Activities 能够经过如下方式来指定:

名称 (如 appActivity: 'com.helloworld.SayHello')。
相对于 appPackage的路径 (如 appPackage: 'com.helloworld', appActivity='.SayHello')

若是“appWaitPackage'和'appWaitActivity”被指定,Appium
将自动等待,直到这些活动的被启动。你能够为实例指定多个等待的activity:

appActivity: 'com.splash.SplashScreen'
appPackage: 'com.splash' appActivity: '.SplashScreen'
appPackage: 'com.splash' appActivity: '.SplashScreen,.LandingPage,com.why.GoThere'

若是你不是很清楚在apk中有哪些activity,你能够经过如下方式来查看:

Mac/Linux: 'adb shell dumpsys window windows | grep mFocusedApp'
在 Ruby 控制台运行: 'adb shell dumpsys window windows`.each_line.grep(/mFocusedApp/).first.strip'
在 Windows 终端运行 'adb shell dumpsys window windows' 而后去看mFocusedApp这一行的内容。

而后执行你的WebDriver测试脚本,脚本必须包含下列的环境参数:

// javascript
{
platformName: 'Android',
platformVersion: '4.4',
deviceName: 'Android Emulator',
app: myApp
}

# python
{
'platformName': 'Android',
'platformVersion': '4.4',
'deviceName': 'Android Emulator',
'app': myApp
}

// php
public static $browsers = array(
array(
'desiredCapabilities' => array(
'platformName' => 'Android',
'platformVersion' => '4.4',
'deviceName' => 'Android Emulator',
'app' => $myApp
)
)
);

// java
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "4.4");
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
capabilities.setCapability(MobileCapabilityType.APP, myApp);

在这个脚本集里,myApp必须是下列其中之一:

一个.apk 或者.zip 档的本地绝对路径
一个包含着你的.apk档的zip压缩档的url
appium安装根目录下的一个示例app的路径

myAppPackage 必须是你的应用的java package,例如, com.example.android.myApp。

myAppActivity 必须是你的但愿测试的Android activity, 例如, MainActivity。

在你选择的WebDriver库里,设定remote session使用上述的环境参数而后使用端口4723来链接本地服务器(或者是使用你在Appium启动时所设定的任意端口)。如今你已经设置完成了!
用Appium测试你的app (Android 设备 < 4.2, 以及混合app测试)

低于4.2版本的Android设备(API Level 17) 没有安装 Google 的UiAutomator framework.下面的范例是早期Appium在这些设备上的测试方法。对于早期的设备以及使用混合模式(webview-based)制做的apps, Appium 包含了另外一种自动化测试工具Selendroid。

要使用Selendroid, 只须要在以前提到的环境参数上稍做修改便可,添加 automationName 参数并指定Seledroid做为测试工具。一般你还须要在你的activity名称前加上. (如:在appActivity参数中使用.MainActivity 而不是 MainActivity) :

// javascript
{
automationName: 'Selendroid',
platformName: 'Android',
platformVersion: '2.3',
deviceName: 'Android Emulator',
app: myApp,
appPackage: 'com.mycompany.package',
appActivity: '.MainActivity'
}

# python
{
'automationName': 'Selendroid',
'platformName': 'Android',
'platformVersion': '2.3',
'deviceName': 'Android Emulator',
'app': myApp,
'appPackage': 'com.mycompany.package',
'appActivity': '.MainActivity'
}

// php
public static $browsers = array(
array(
'desiredCapabilities' => array(
'automationName' => 'Selendroid',
'platformName' => 'Android',
'platformVersion' => '2.3',
'deviceName' => 'Android Emulator',
'app' => $myApp,
'appPackage' => 'com.mycompany.package',
'appActivity'=> '.MainActivity'
)
)
);

// java
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, "Selendroid");
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "2.3");
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
capabilities.setCapability(MobileCapabilityType.APP, myApp);
capabilities.setCapability(MobileCapabilityType.APP_PACKAGE: "com.mycompany.package");
capabilities.setCapability(MobileCapabilityType.APP_ACTIVITY: ".MainActivity");

这样Appium就会启动 Selendroid 测试会话取代默认的测试会话。使用Selendroid的缺点是有时候它的API跟Appium很是不一样。因此咱们建议你在为你的旧设备或者混合app写测试脚本以前先仔细的阅读Selendroid的说明文档。

5.8 服务器参数
Appium 服务器参数

使用方法: node . [标志]
服务器标志

全部的标志都是可选的,可是有一些标志须要组合在一块儿才能生效。

<expand_table>
标志 默认值 描述 例子
--shell null 进入 REPL 模式
--localizable-strings-dir en.lproj IOS only: 定位 .strings所在目录的相对路径 --localizable-strings-dir en.lproj
--app null iOS: 基于模拟器编译的 app 的绝对路径或者设备目标的 bundle_id; Android: apk 文件的绝对路径--app /abs/path/to/my.app
--ipa null (IOS-only) .ipa 文件的绝对路径 --ipa /abs/path/to/my.ipa
-U, --udid null 链接物理设备的惟一设备标识符 --udid 1adsf-sdfas-asdf-123sdf
-a, --address 0.0.0.0 监听的 ip 地址 --address 0.0.0.0
-p, --port 4723 监听的端口 --port 4723
-ca, --callback-address null 回调IP地址 (默认: 相同的IP地址) --callback-address 127.0.0.1
-cp, --callback-port null 回调端口号 (默认: 相同的端口号) --callback-port 4723
-bp, --bootstrap-port 4724 (Android-only) 链接设备的端口号 --bootstrap-port 4724
-k, --keep-artifacts false 弃用,无效。trace信息如今保留tmp目录下,每次运行前会清除该目录中的信息。 也能够参考 --trace-dir 。
-r, --backend-retries 3 (iOS-only) 遇到 crash 或者 超时,Instrument 从新启动的次数。 --backend-retries 3
--session-override false 容许 session 被覆盖 (冲突的话)
--full-reset false (iOS) 删除整个模拟器目录。 (Android) 经过卸载应用(而不是清除数据)重置应用状态。在 Android 上,session 完成后也会删除应用。
--no-reset false session 之间不重置应用状态 (iOS: 不删除应用的 plist 文件; Android: 在建立一个新的 session 前不删除应用。)
-l, --pre-launch false 在第一个 session 前,预启动应用 (iOS 须要 --app 参数,Android 须要 --app-pkg 和 --app-activity)
-lt, --launch-timeout 90000 (iOS-only) 等待 Instruments 启动的时间
-g, --log null 将日志输出到指定文件 --log /path/to/appium.log
--log-level debug 日志级别; 默认 (console[:file]): debug[:debug] --log-level debug
--log-timestamp false 在终端输出里显示时间戳
--local-timezone false 使用本地时间戳
--log-no-colors false 不在终端输出中显示颜色
-G, --webhook null 同时发送日志到 HTTP 监听器 --webhook localhost:9876
--native-instruments-lib false (IOS-only) iOS 内建了一个怪异的不可能避免的延迟。咱们在 Appium 里修复了它。若是你想用原来的,你可使用这个参数。
--app-pkg null (Android-only) 你要运行的apk的java包。 (例如, com.example.android.myApp) --app-pkg com.example.android.myApp
--app-activity null (Android-only) 打开应用时,启动的 Activity 的名字(好比, MainActivity) --app-activity MainActivity
--app-wait-package false (Android-only) 你想等待的 Activity 的包名。(好比, com.example.android.myApp) --app-wait-package com.example.android.myApp
--app-wait-activity false (Android-only) 你想等待的 Activity 名字(好比, SplashActivity) --app-wait-activity SplashActivity
--android-coverage false (Android-only) 彻底符合条件的 instrumentation 类。 做为命令 adb shell am instrument -e coverage true -w 的 -w 的参数 --android-coverage com.my.Pkg/com.my.Pkg.instrumentation.MyInstrumentation
--avd null (Android-only) 要启动的 avd 的名字
--avd-args null (Android-only) 添加额外的参数给要启动avd --avd-args -no-snapshot-load
--device-ready-timeout 5 (Android-only) 等待设备准备好的时间,以秒为单位 --device-ready-timeout 5
--safari false (IOS-Only) 使用 Safari 应用
--device-name null 待使用的移动设备名字 --device-name iPhone Retina (4-inch), Android Emulator
--platform-name null 移动平台的名称: iOS, Android, or FirefoxOS --platform-name iOS
--platform-version null 移动平台的版本 --platform-version 7.1
--automation-name null 自动化工具的名称: Appium or Selendroid --automation-name Appium
--browser-name null 移动浏览器的名称: Safari or Chrome --browser-name Safari
--default-device, -dd false (IOS-Simulator-only) 使用instruments本身启动的默认模拟器
--force-iphone false (IOS-only) 不管应用要用什么模拟器,强制使用 iPhone 模拟器
--force-ipad false (IOS-only) 不管应用要用什么模拟器,强制使用 iPad 模拟器
--language null iOS / Android 模拟器的语言 --language en
--locale null Locale for the iOS simulator / Android Emulator --locale en_US
--calendar-format null (IOS-only) iOS 模拟器的日历格式 --calendar-format gregorian
--orientation null (IOS-only) 初始化请求时,使用 LANDSCAPE (横屏) 或者 PORTRAIT (竖屏) --orientation LANDSCAPE
--tracetemplate null (IOS-only) 指定 Instruments 使用的 tracetemplate 文件 --tracetemplate /Users/me/Automation.tracetemplate
--show-sim-log false (IOS-only) 若是设置了, iOS 模拟器的日志会写到终端上来
--show-ios-log false (IOS-only) 若是设置了, iOS 系统的日志会写到终端上来
--nodeconfig null 指定 JSON 格式的配置文件 ,用来在 selenium grid 里注册 appiumd --nodeconfig /abs/path/to/nodeconfig.json
-ra, --robot-address 0.0.0.0 robot 的 ip 地址 --robot-address 0.0.0.0
-rp, --robot-port -1 robot 的端口地址 --robot-port 4242
--selendroid-port 8080 用来和 Selendroid 交互的本地端口 --selendroid-port 8080
--chromedriver-port 9515 ChromeDriver运行的端口 --chromedriver-port 9515
--chromedriver-executable null ChromeDriver 可执行文件的完整路径
--use-keystore false (Android-only) 设置签名 apk 的 keystore
--keystore-path (Android-only) keystore 的路径
--keystore-password android (Android-only) keystore 的密码
--key-alias androiddebugkey (Android-only) Key 的别名
--key-password android (Android-only) Key 的密码
--show-config false 打印 Appium 服务器的配置信息,而后退出
--no-perms-check false 跳过Appium对是否能够读/写必要文件的检查
--command-timeout 60 默认全部会话的接收命令超时时间 (在超时时间内没有接收到新命令,自动关闭会话)。 会被新的超时时间覆盖
--keep-keychains false (iOS) 当 Appium 启动或者关闭的时候,是否保留 keychains (Library/Keychains)
--strict-caps false 若是所选设备是appium不认可的有效设备,会致使会话失败
--isolate-sim-device false Xcode 6存在一个bug,那就是一些平台上若是其余模拟器设备先被删除时某个特定的模拟器只能在没有任何错误的状况下被创建。这个选项致使了Appium不得不删除除了正在使用设备之外其余全部的设备。请注意这是永久性删除,你可使用simctl或xcode管理被Appium使用的设备类别。
--tmp null 能够被Appium用来管理临时文件的目录(绝对路径),好比存放须要移动的内置iOS应用程序。 默认的变量为 APPIUM_TMP_DIR ,在 *nix/Mac 为 /tmp 在windows上使用环境便令 TEMP 设定的目录。
--trace-dir null 用于保存iOS instruments trace的 appium 目录,是绝对路径, 默认为 <tmp dir>/appium-instruments
--intent-action android.intent.action.MAIN (Android-only) 用于启动 activity 的intent action --intent-action android.intent.action.MAIN
--intent-category android.intent.category.LAUNCHER (Android-only) 用于启动 activity 的intent category --intent-category android.intent.category.APP_CONTACTS
--intent-flags 0x10200000 (Android-only) 启动 activity 的标志 --intent-flags 0x10200000
--intent-args null (Android-only) 启动 activity 时附带额外的 intent 参数 --intent-args 0x10200000
--suppress-adb-kill-server false (Android-only) 若是被设定,阻止Appium杀掉adb实例。

5.9 移动手势的自动化
移动手势的自动化

虽然Selenium WebDriver的规范支持数种手机交互的方式,但它的参数并不能简单地映射到底层设备使用的自动化函数 (像在iOS上的UIAutomation) 。为此,Appium在规范的最新版本中定义了新的触摸操做/多点触控 API
(https://dvcs.w3.org/hg/webdriver/raw-file/tip/webdriver-spec.html#multiactions-1)。
注意,这跟在早期版本中使用原始JSON Wire Protocol 的触摸操做 API不一样。

这些API可让你使用多个驱动来创建任意手势。请参阅对应语言的Appium客户端文档,就能够找到使用这些API的例子。
触摸操做/多点触控 API的概述
触摸操做 (TouchAction)

TouchAction 对象包含一连串的事件。

在全部的appium客户端库中,触摸对象建立并给出一连串的事件。

规范中的可用事件有:
* 短按 (press)
* 释放 (release)
* 移动到 (moveTo)
* 点击 (tap)
* 等待 (wait)
* 长按 (longPress)
* 取消 (cancel)
* 执行 (perform)

这里有一个经过伪代码建立动做的例子:

TouchAction().press(el0).moveTo(el1).release()

上述模拟用户按下一个元素,滑动他的手指到另外一个位置,而后从屏幕上释放其手指。

Appium按顺序执行这些事件。你能够添加一个 wait 事件来控制相应手势的时间。

appium客户端库有不一样的方式来实现上述例子,好比:你能够传递一个坐标值或一个元素给 moveTo 事件。同时传递坐标和元素,会将坐标和元素对应起来,但这不是绝对的。

调用 perform 事件发送整个事件序列给appium,从而使触摸手势在设备上运行。

Appium客户端还容许人们直接经过驱动程序对象执行触摸操做, 而不是调用触摸操做对象的perform事件。

在伪代码中,如下两个是等价的:

TouchAction().tap(el).perform()

driver.perform(TouchAction().tap(el))

多点触控 (MultiTouch)

MultiTouch 对象是触摸操做的集合。

多点触控手势只有两个方法,添加 (add) 和执行 (perform) 。

add 用于将不一样的触摸操做添加到一个多点触控中。

当 perform 被调用的时候,全部被添加到多点触摸中的触摸事件会被发送到appium而且被执行,就像它们同时发生同样。Appium会执行“触摸事件”中的第一个事件,而后第二个,以此类推。

用两只手指点击的代码示例:

action0 = TouchAction().tap(el)
action1 = TouchAction().tap(el)
MultiAction().add(action0).add(action1).perform()

缺陷和解决方法

不幸的是有一个缺陷存在于iOS的7.x的模拟器上,ScrollViews没法识别由UIAutomation建立的手势 (在iOS上Appium使用的是UIAutomation) 。 为了实现此功能,咱们已经提供了新的函数, scroll, 在大部分状况下可让你实现跟ScrollView同样的功能!

滚动

要使用这特殊的功能,咱们重写了driver中的 execute 和
executeScript 方法。 能够经过在命令前加 mobile: 的前缀来使用滚动。
请参见下面的例子:

WD.js:

// javascript
// 把视图往下滑动
driver.execute("mobile: scroll", [{direction: 'down'}])
// 继续测试

Java:

// java
JavascriptExecutor js = (JavascriptExecutor) driver;
HashMap<String, String> scrollObject = new HashMap<String, String>();
scrollObject.put("direction", "down");
scrollObject.put("element", ((RemoteWebElement) element).getId());
js.executeScript("mobile: scroll", scrollObject);

滑块的自动化

iOS

Java

// java
// 滑动值使用0到1之间的数字以字符串的形式表示
// 例如,“0.1”表明10%,“1.0”表明100%
WebElement slider = driver.findElement(By.xpath("//window[1]/slider[1]"));
slider.sendKeys("0.1");

Android

与Android上的滑块进行交互的最佳方式是用触摸操做 (TouchActions) 。

5.10 uiautomator UiSelector
uiautomator UiSelector

Appium可使用 UiSelectors
进行元素查找,同时也支持UiScrollable
.

注意:根据索引 (index) 进行查找并不可靠,请使用实例 (instance) 代替. 下面的示范是用Ruby语言编写的、针对 api demo (这是一个 appium 测试用的应用) 的实例。

翻译者备注:UiSelectors 和 UiScrollable 均是 Android UiAutomator 中的对象,所以如下用法仅适用于 Android 。

找到第一个文本控件 (TextView) 。

# ruby
first_textview = find_element(:uiautomator, 'new UiSelector().className("android.widget.TextView").instance(0)');

根据文本 (text) 找到第一个元素。

# ruby
first_text = find_element(:uiautomator, 'new UiSelector().text("Animation")')
first_text.text # "Animation"

找到第一个可滚动的元素, 而后找到文本是 "Tabs" 的文本控件。
"Tabs" 元素就是将要滚动到的控件。

# ruby
element = find_element(:uiautomator, 'new UiScrollable(new UiSelector().scrollable(true).instance(0)).getChildByText(new UiSelector().className("android.widget.TextView"), "Tabs")')

scrollIntoView 是一个特例,会返回滚动到指定控件的元素。
scrollIntoView 对任何的 UiSelector 均可以执行滚动操做。

# ruby
element = find_element(:uiautomator, 'new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("WebView").instance(0));')
element.text # "WebView"

5.11 多语言支持
多语言支持

程序处理非拉丁字符时存在一个的问题:对于带音标的字符,存在多种编码形式。例如,对于é这样的字符,有两种编码方式:一种是单独的字符é(Unicode中的LATIN SMALL LETTER E WITH ACUTE(带有音标的小写的拉丁字母'E')),另外一种是音标在字符后边(COMBINING ACUTE ACCENT(字符和音标的组合))。为了解决这个问题,存在一个normalization (标准化) 方法,让"每一个字符都有一个惟一的二进制表示"。

幸运的是,对ASCII字符(例如 不须要进行标准化的字符)进行标准化将不会产生任何变化,而且屡次进行标准化
操做也不会发生额外的变化。所以,能够对全部字符使用标准化函数而不用担忧产生不良影响。

// javascript
var unorm = require('unorm');

'some ASCII text' === unorm.nfd('some ASCII text');
unorm.nfd('Adélaïde Hervé') === unorm.nfd(unorm.nfd('Adélaïde Hervé'));

在测试的时候遇到Unicode字符,你须要对字符进行标准化,确保指望的值和接收到的值一致。
有不少方法能够用来进行标准化,因此你要确保执行的是一样的方法!

// javascript
var unorm = require('unorm');
driver
.elementByAccessibilityId('find')
.text()
.then(function (txt) {
unorm.nfd(txt).should.be(unorm.nfd("é Œ ù ḍ"));
});

一个由不一样unicode文本编码致使的问题的标志是断言失败但报告却显示两个看起来如出一辙的字符串:

AssertionError: expected 'François Gérard' to deeply equal 'François Gérard'
+ expected - actual

+"François Gérard"
-"François Gérard"

当发生只因编码致使的问题时,输出看上去同样。从标准的角度,它们的编码应该也和它们看上去那样相同。
查找器 (Finder)

须要被查找的字符也应该须要标准化。好比,你在一个iOS的app上有一个叫作Найти的按钮,你也应该在find命令中标准化它。

// javascript
var unorm = require('unorm');
driver
.findElementByXPath(unorm.nfd("//UIAButton[@name='Найти']"))
.should.eventually.exist;

不然这个按钮可能没法被找到。
文本框 (Text Field)

默认状况下,iOS和Android的自动化工具都不支持向输入框输入非ASCII字符。
iOS

Appium 彻底绕过键盘直接向iOS设备的输入框发送非ASCII字符。虽然这让这些文本在测试中被成功输入,但必须记住由键盘输入触发的业务逻辑将不会被测试到。

像上边说的同样,断言收到的文本前应该先标准化它。

// javascript
var unorm = require('unorm');
var testText = unorm.nfd("é Œ ù ḍ");
driver
.elementsByClassName('UIATextField').at(1)
.sendKeys(testText)
.text()
.should.become(testText)
.nodeify(done);

Android

经过下载并安装一个特殊键盘 , Android 能够支持输入 Unicode 字符,这个输入法容许文本经过ASCII在Appium和被测应用之间进行通信。

为了使用这个功能,将unicodeKeyboard设置为true。若是想要键盘设置在测试完成后自动回到原始状态,
将resetKeyboard设置为true。不然Appium测试结束后,Appium的Unicode键盘仍然会被激活。

翻译备注:这个Unicode键盘并不是虚拟键盘,在界面上不会显示出来,因此要进行其余类型的测试必须切换回其余输入法。

测试时能够经过send_keys向输入框输入Unicode字符。

// javascriptvar desired = {app: '/path/to/app',deviceName: 'Android Emulator',deviceVersion: '4.4',platformName: 'Android',unicodeKeyboard: true,resetKeyboard: true};var testText = 'é Œ ù ḍ';driver.elementByClassName('android.widget.EditText').sendKeys(testText).text().should.eventually.become(testText).nodeify(done);

相关文章
相关标签/搜索