Appium中文使用指南

前言:

前段時間學習Android自動化測試,網上關于Appium的介紹和學習資料比較散亂,大多不齊全,官網API看的也是一臉懵,所以決定自己整理一份文檔,供自己學習,也希望能幫助到正在學習Appium和自動化測試的朋友們。
在本地寫了一個md文檔之后,放到了GitHub上維護。鑒于簡書的顏值,我決定轉戰簡書寫博客,但是簡書的Markdown貌似不只是頁內錨點跳轉,所以本文的所有錨點都無效了。文章有些長,需要pdf的朋友們可以去我的GitHub上拿。

為什么選擇Appium

學習Android自動化測試的時候,看了google官方推薦的幾個工具和測試框架,比如Espresso和UI Automator,其中在使用UI Automator來做UI自動化測試的時候,發生一點問題:向控件輸入字符的時候無效!不管是中文還是英文都無法輸入,而且最終竟然還顯示測試通過。經過多方搜索都找不到解決辦法,最終還是選擇Appium,并且Appium是跨平臺的,可以測試ios和Android還有webApp;其中Android平臺上是基于UI Automator的,所以可以無縫切換使用UI Automator的API。


作者:GeeJoe
郵箱:geejoe_developer@outlook.com
GitHub:https://github.com/GeeJoe/AppiumDoc
更新時間:2017-09-14 16:44

Appium使用指南


環境配置

  • 安裝Nodejs
  • 安裝Appium
  • 配置IDE

安裝NodeJs

Nodejs官網 下載最新版本的NodeJs并直接安裝。安裝完畢后,打開命令行,輸入 node -v ,出現類似下面的信息說明安裝成功。

V4.0.0

安裝Appium

Appium 官網 載和你所使用系統一致的版本進行安裝。

驗證安裝

當確認Appium安裝完畢后,我們可以通過 appium-doctor 的命令來檢查當前appium安裝是否完善,當前的JDK、SDK等環境是否配置正確。

如果 appium-doctor 返回的內容是有錯的,請根據返回的具體的提示,將你的環境搭建完善。
如果返回的結果類似如下,說明安裝成功

...
...
Android Checks were successful.
All Checks were successful

需要注意的是,如果你是通過安裝包安裝的,使用 appium-doctor 命令時必須切換到
C:\Program Files (x86)\Appium\node_modules.bin 目錄;為了方便,需要把.bin目錄添加到環境變量Path中。

配置IDE

配置AndroidStudio

  1. 新建一個項目,AndroidStudio新建項目會自動生成一個 androidTest 包和 test
  2. 下載 Appium java clientSelenium Java standalone server 兩個庫對應的 jar 包
  3. 將兩個jar包復制到項目module里的 libs 目錄
  4. 選擇兩個jar包,單擊鼠標右鍵,選擇Add as Library
  5. 配置成功,可以在 test 包中新建測試用例了

啟動Appium Server

通過圖形化界面啟動

雙擊Appium圖標,打開Appium應用

appium_start.png

點擊箭頭所指的按鈕即可啟動

從命令行啟動

只需要一個命令:

appium

若顯示如下信息則啟動成功:

info: Welcome to Appium v1.4.16 (REV ae6877eff263066b26328d457bd285c0cc62430d)
info: Appium REST http interface listener started on 0.0.0.0:4723
info: Console LogLevel: debug

若需要退出,按下 ctrl+c 即可

配置啟動參數

啟動時可以手動配置參數,了解所有參數,可查閱 Appium 官方文檔

標志 默認值 描述 例子
-a , --address 0.0.0.0 監聽的 ip 地址。注意在圖形化界面上默認值為 127.0.0.1 --address 0.0.0.0
-p , --port 4723 監聽的端口。需要啟動多個 appium server 進行并行測試時需要保證每個server 的監聽端口不一樣。 --port 4723
--log-timestamp false 在日志輸出里顯示時間戳
--local-timezone false 在日志輸出的時間戳使用本地時間
-g , --log null 將日志輸出到指定文件 --g /path/to/appium.log
--session-override false 允許 session 被覆蓋 (沖突的話)
--command-timeout 60 默認所有會話的接收命令超時時間 (在超時時間內沒有接收到新命令,自動關閉會話)。 會被新的超時時間覆蓋

這些參數同樣可以在圖形界面設置:

setting.png

學習DesiredCapabilities

DesiredCapabilities簡介

DesiredCapabilities 攜帶了一些配置信息,在啟動session的時候是必須提供,如啟動模式、apk/app配置、package/activity配置、瀏覽器配置、鍵盤配置等。

Desired Capabilities關鍵字

Desired Capabilities的重要作用是在啟動時傳遞信息給Appium Server。
下表中列舉了Appium常用的 Desired Capabilities 關鍵字。

描述
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 的 instruments -s devices 命令可返回一個有效的設備的列表。在 Andorid 上雖然這個參數目前已被忽略,但仍然需要添加上該參數
app 本地絕對路徑遠程 http URL 所指向的一個安裝包(.ipa,.apk,或 .zip 文件)。Appium 將其安裝到合適的設備上。請注意,如果您指定了 appPackageappActivity 參數(見下文),Android 則不需要此參數了。該參數也與 browserName 不兼容。 /abs/path/to/my.apkhttp://myapp.com/app.ipa
browserName 做自動化時使用的瀏覽器名字。如果是一個應用則只需填寫個空的字符串 'Safari' 對應 iOS,'Chrome', 'Chromium', 或 'Browser' 則對應 Android
newCommandTimeout 用于客戶端在退出或者結束 session 之前,Appium 等待客戶端發送一條新命令所花費的時間(秒為單位) 例如 60
language (Sim/Emu-only) 為模擬器設置語言 例如 fr
locale (Sim/Emu-only) 為模擬器設置所在區域 例如 fr_CA
udid 連接真機的唯一設備號 例如 1ae203187fc012g
orientation (Sim/Emu-only) 模擬器當前的方向 豎屏橫屏
autoWebview 直接轉換到 Webview 上下文(context)。默認值為 false true, false
noReset 在當前 session 下不會重置應用的狀態。默認值為 false true, false
fullReset (iOS)刪除所有的模擬器文件夾。(Android) 要清除 app 里的數據,請將應用卸載才能達到重置應用的效果。在 Android, 在 session 完成之后也會將應用卸載掉。默認值為 false true, false

Android 獨有

描述
appActivity Activity 的名字是指從你的包中所要啟動的 Android acticity。他通常需要再前面添加. (例如 使用 .MainActivity 代替 MainActivity MainActivity, .Settings
appPackage 運行的 Android 應用的包名 com.example.android.myApp, com.android.settings
appWaitActivity 用于等待啟動的 Android Activity 名稱 SplashActivity
appWaitPackage 用于等待啟動的 Android 應用的包 com.example.android.myApp, com.android.settings
appWaitDuration 用于等待 appWaitActivity 啟動的超時時間(以毫秒為單位)(默認值為 20000) 30000
deviceReadyTimeout 用于等待模擬器或真機準備就緒的超時時間 5
androidCoverage 用于執行測試的 instrumentation 類。 傳送 -w 參數到如下命令 adb shell am instrument -e coverage true -w com.my.Pkg/com.my.Pkg.instrumentation.MyInstrumentation
enablePerformanceLogging (僅適用于 Chrome 與 webview)開啟 Chromedriver 的性能日志。(默認值為 false true, false
androidDeviceReadyTimeout 用于等待設備在啟動應用后準備就緒的超時時間。以秒為單位。 例如 30
androidInstallTimeout 用于等待在設備中安裝 apk 所花費的時間(以毫秒為單位)。默認值為 90000 例如 90000
adbPort 用來連接 ADB 服務器的端口(默認值為 5037 5037
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 truefalse
keystorePath 自定義 keystore 的路徑, 默認路徑為 ~/.android/debug.keystore 例如 /path/to.keystore
keystorePassword 自定義 keystore 的密碼 例如 foo
keyAlias key 的別名 例如 androiddebugkey
keyPassword key 的密碼 例如 foo
chromedriverExecutable webdriver 可執行文件的絕對路徑(如果 Chromium 內嵌一個自己提供的 webdriver,則應使用他去替換掉 Appium 自帶的 chromedriver) /abs/path/to/webdriver
autoWebviewTimeout 用于等待 Webview 上下文(context)激活的時間(以毫秒為單位)。默認值為 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>, 等等。
dontStopAppOnReset 在使用 adb 啟動應用之前,不要終止被測應用的進程。如果被測應用是被其他鉤子(anchor)應用所創建的,設置該參數為 false 后,就允許鉤子(anchor)應用的進程在使用 adb 啟動被測應用期間仍然存在。換而言之,設置 dontStopAppOnResettrue 后,我們在 adb shell am start 的調用中不需要包含 -S標識(flag)。忽略該 capability 或 設置為 false 的話,就需要包含 -S 標識(flag)。默認值為 false truefalse
unicodeKeyboard 使用 Unicode 輸入法。 默認值為 false truefalse
resetKeyboard 在設定了 unicodeKeyboard 關鍵字的 Unicode 測試結束后,重置輸入法到原有狀態。如果單獨使用,將會被忽略。默認值為 false truefalse
noSign 跳過檢查和對應用進行 debug 簽名的步驟。僅適用于 UiAutomator,不適用于 selendroid。 默認值為 false truefalse
ignoreUnimportantViews 調用 uiautomator 的函數 setCompressedLayoutHierarchy()。由于 Accessibility 命令在忽略部分元素的情況下執行速度會加快,這個關鍵字能加快測試執行的速度。被忽略的元素將不能夠被找到,因此這個關鍵字同時也被實現成可以隨時改變的 設置 ( settings )。 默認值為 false truefalse
disableAndroidWatchers 禁用 android 監視器(watchers)。監視器用于監視應用程序的無響應狀態(anr)和崩潰(crash),禁用會降低 Android 設備或模擬器的 CPU 使用率。該 capability 僅在使用 UiAutomator 時有效,不適用于 selendroid,默認設置為 false truefalse
chromeOptions 允許對 ChromeDriver 傳 chromeOptions 的參數。了解更多信息請查閱 chromeOptions chromeOptions: {args: ['--disable-popup-blocking']}
recreateChromeDriverSessions 當移除非 ChromeDriver webview時,終止掉 ChromeDriver 的 session。默認設置為 false truefalse
nativeWebScreenshot 在 web 的上下文(context),使用原生(native)的方法去截圖,而不是用過代理的 ChromeDriver。默認值為 false truefalse
androidScreenshotPath 在設備中截圖被保存的目錄名。默認值為 /data/local/tmp 例如 /sdcard/screenshots/
autoGrantPermissions 讓Appium自動確定您的應用需要哪些權限,并在安裝時將其授予應用。默認設置為 false truefalse

Session簡介

Session 是指我們的測試腳本從打開應用到最終執行完畢關閉應用的整個過程。
對于測試腳本,從申請到退出一個 session 的整個過程如下:

//打開一個應用,也可以稱為“申請一個Session”
AndroidDriver driver = new AndroidDriver<>(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);

//此處的所有代碼處于一個Session中
...

//關閉應用,也可以稱為“退出一個Session”
driver.quit();

元素定位

方法名 參數 描述
findElementByName String
元素name屬性
通過元素name屬性查找,在Android中一般可以用text代替
findElementByAndroidUIAutomator String
Ui Automator查找代碼
使用UI Automator來查找元素
findElementByClassName String
類名,要寫全路徑:android.weight.TextView
通過元素類名查找
findElementById String
元素id,android:id/title
通過元素id查找
findElementByAccessibilityId String
元素的contentDescription屬性
通過contentDescription屬性查找
findEelementByXPath String
元素的XPath
通過XPath查找
findElementByCssSelector WebView專用
findElementByLinkText WebView專用
findElementByPartialLinkText WebView專用

注: 每一個方法對應著一個findElementsBy***方法,后者返回一個Element集合List,表示一個符合查找規則的一個Element集合

findElementByName

在Android中,沒有合適的方法可以找到控件的Name屬性,但是大多數情況下可以用控件的text代替name。

findElementByAndroidUIAutomator

使用UI Automator查找控件:

WebElement el = driver.findElementByAndroidUIAutomator("new UiSelector().text(\"Add note\")");

更多關于UI Automator定位元素的方法,詳見:UI Automator定位元素

findElementByClassName

WebElement el = driver.findElementByClassName("android.weight.TextView");

findElementById

WebElement el = driver.findElementById("android:id/title");

如果目標設備的API Level低于18則UIAutomatorViewer不能獲得對應的Resource ID,只有等于大于18的時候才能使用。

findElementByAccessibilityId

WebElement el = driver.findElementByAccessibilityId("menu_add_note_description");

Accessibility ID在Android上面就等同于contentDescription

findEelementByXPath

WebElement el = driver.findElementByXPath("http://android.widget.TextView[contains(@text,'Add note')]");  

xPath是一種路徑,在uiautomatorviewer中可以查看當前頁面的元素層級,XPath就是用來描述這種層級關系的一種路徑表達方式,比如,下圖中的例子,想找列表中第二個note1,則可以這樣寫:

UIAutomatorviewer.png
WebElement el = driver.findElementByXPath("http://android.widget.LinearLayout[1]/android.widget.FrameLayout/android.widget.ListView/android.widget.TextView[contains(@index,0)]");  

findElementByCssSelector

這個方法是針對WebView容器下面的控件定位的,因為現在針對的是Native App暫時還沒有用到,所以先標記下,今后需要的時候加上去。

findElementByLinkText

這個方法是針對WebView容器下面的控件定位的,因為現在針對的是Native App暫時還沒有用到,所以先標記下,今后需要的時候加上去。

findElementByPartialLinkText

這個方法是針對WebView容器下面的控件定位的,因為現在針對的是Native App暫時還沒有用到,所以先標記下,今后需要的時候加上去。

UI Automater定位元素

UI Automator中主要通過UISelector類查找元素

通過文本信息定位

返回值 方法名 說明 用法
UiSelector text(String text) 根據“控件text屬性的內容”構造出UiSelector對象 例如,一個控件text的值是“發現”,UiSelector s = new UiSelector().text("發現");
UiSelector textContains(String text) 根據“控件text屬性包含的內容”構造出UiSelector對象 同上例子:UiSelector s = new UiSelector().textContains("現");
UiSelector textMatches(String regex) 根據“控件text屬性正則表達式的內容”構造出UiSelector對象 正則表達式語法參考網上資料
UiSelector textStartsWith(String text) 根據“控件text屬性開始的內容”構造出UiSelector對象 同上例子:UiSelector s = new UiSelector().textStartsWith("發");

通過description定位

返回值 方法名 說明
UiSelector description(String desc) 根據“控件content-desc屬性的內容”構造出UiSelector對象
UiSelector descriptionContains(String desc) 包含**
UiSelector descriptionMatches(String regex) 正則
UiSelector descriptionStartsWith(String desc) 以**開始

通過ResourceId定位

返回值 方法名 說明
UiSelector resourceId(String id) 根據資源id獲取對象,例如:UiSelector s = new UiSelector().resourceId("com.tencent.mm:id/b8m")
UiSelector resourceIdMatches(String regex) 根據資源id的正則表達式獲取對象

通過類名定位

返回值 方法名 說明
UiSelector className(String className) 根據控件類名找到對象
UiSelector classNameMatches(String regex) 根據類名的正則表達式獲取對象
UiSelector instance(int instance) 找到一個擁有相同屬性的對象集合中的對象,例如:UiSelector s = new UiSelector().className("android.widget.TextView").instance(1);可以找到頁面層級中第二個類名為TextView的元素
UiSelector index(int index) 用法和上面的instance差不多,谷歌的原文說這個方法是unreliable的,推薦使用instance方法

通過層級關系

返回值 方法名 說明
UiSelector fromParent(UiSelector s) 獲取同一個父控件的其他子控件,即獲取兄弟控件
UiSelector getFromParent(UiSelector s) 獲取同一個父控件的其他子控件,即獲取兄弟控件
UiSelector childSelector(UiSelector s) 獲取子控件
UiSelector getChild(UiSelector s) 獲取子控件

使用JUnit組織測試用例

使用JUnit來組織Appium測試用例,可以添加@Before@Test或者@After等注解來使測試代碼的運行變得更加靈活。

比如在開始測試之前,需要配置Capability和連接Appium服務器,而且一般需要安裝應用或者打開應用的某個Activity。這時候可把這些操作放到一個方法中,并且方法添加@Before注解,則在運行的時候,@Before方法會先于@Test方法執行。

同理,測試結束后需要關閉session,回收資源等等,可以把這些操作放到一個@After方法中,@After方法在所有@Test方法結束之后執行。

顯式等待和隱式等待

有時候,由于網絡或者其他原因,頁面跳轉之后,某些元素沒有立即顯示出來,此時查找元素會失敗。這種情況就需要引入顯式等待隱式等待

線程等待

直接使用Thread.sleep();

隱式等待

driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

全局等待30秒,不管元素是否已經加載

顯式等待

WebDriverWait 顯示等待,顯示等待時間可以通過 WebDriverWaitutil 來決定,比如這個 timeOut 是60,如果該元素60s以內出現就不在等待。

WebDriverWait wait = new WebDriverWait(driver, 60);
    WebElement e= wait.until(new  ExpectedCondition<WebElement>() {
            @Override
            public WebElement apply(WebDriver d) {
                return d.findElement(By.id("q"));
            }
        })
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,106評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,441評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,211評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,736評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,475評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,834評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,829評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,009評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,559評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,306評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,516評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,038評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,728評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,132評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,443評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,249評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,484評論 2 379

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,728評論 25 708
  • 前言:本篇文章并非我的原創,而是翻譯自英文原著。這里的每一句話我都仔細揣摩過并且加以實踐,著實花了一些時間,在此記...
    顧顧314閱讀 22,054評論 0 19
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,826評論 18 139
  • 前言 做Android端功能自動化已有2年多的時間了,使用過的功能自動化框架有Robotium、Uiautomat...
    海波筆記閱讀 17,070評論 3 66
  • 第一個游戲,把身上的貼紙甩下來,棉質衣服不好甩,最后卡卡用手扯掉然后說,這個游戲不好玩 媽媽畫畫孩子猜,我畫了漢堡...
    山青愛自我探索閱讀 194評論 0 0