該文檔是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);