中文Appium API 文檔


該文檔是Testerhome官方翻譯的
源地址:https://github.com/appium/appium/tree/master/docs/cn
官方網站上的:http://appium.io/slate/cn/master/?ruby#about-appium

中文Appium API 文檔

第一章:關於appium
1.1 appium客戶端
客戶端類庫列表及Appium服務端支持

這些類庫封裝了標准Selenium客戶端類庫,為用戶提供所有常見的JSON 格式selenium命令以及額外的移動設備控制相關的命令,如多點觸控手勢和屏幕朝向。

Appium客戶端類庫實現了Mobile JSON Wire Protocol(一個標准協議的官方擴展草稿)和W3C Webdriver spec(一個傳輸不可預知的自動化協議,該協議定義了MultiAction 接口)的元素。

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-appiumlibrary

1.2 appium介紹
Appium 介紹

Appium 是一個自動化測試開源工具,支持 iOS 平台和 Android 平台上的原生應用,web 應用和混合應用。

所謂的“移動原生應用”是指那些用 iOS 或者 Android SDK 寫的應用。所謂的“移動 web 應用”是指使用移動瀏覽器訪問的應用(Appium 支持 iOS 上的 Safari 和 Android 上的 Chrome)。所謂的“混合應用”是指原生代碼封裝網頁視圖——原生代碼和 web 內容交互。比如,像 Phonegap,可以幫助開發者使用網頁技術開發應用,然后用原生代碼封裝,這些就是混合應用。

重要的是,Appium 是一個跨平台的工具:它允許測試人員在不同的平台(iOS,Android)使用同一套API來寫自動化測試腳本,這樣大大增加了 iOS 和 Android 測試套件間代碼的復用性。

想知道 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字符。

// javascript
var 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);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM