終於到了“啥也不干躺在家就能給社會做貢獻”的時候,但有夢想的測試人從不會讓自己的生活變得無聊!與其宅在家里數瓜子殼,還不如利用整塊時間提升測試開發技能!

定制化配置
自動遍歷測試技術以及工具該如何選擇和快速入門?經過對比和需求,最終選擇測試架構師思寒大佬的 AppCrawler 作為自動遍歷測試的工具。以下就分享 AppCrawler 自動遍歷測試的一些最佳實踐經驗。
模板文件生成
運行命令java -jar appcrawler-2.4.0-jar-with-dependencies.jar --demo, 會在當前目錄下生成一個 demo.yml 文件,這個文件就是我們進行定制化的配置文件模板:
#執行命令生成demo.yaml模板配置文件
$ java -jar appcrawler-2.4.0-jar-with-dependencies.jar --demo
2019-12-01 21:33:35 INFO [AppCrawler$.86.main]
----------------
AppCrawler 2.4.0 [霍格沃茲測試學院特別紀念版]
Appium 1.8.1 Java8 tested
app爬蟲, 用於自動遍歷測試. 支持Android和iOS, 支持真機和模擬器
項目地址: https://github.com/seveniruby/AppCrawler
移動測試技術交流: https://testerhome.com
聯絡作者: seveniruby@testerhome.com (思寒)
致謝: 曉光 泉龍 楊榕 恆溫 mikezhou yaming116 沐木
--------------------------------
2019-12-01 21:33:35 INFO [AppCrawler$.223.parseParams] use default appium address 4723
2019-12-01 21:33:35 INFO [AppCrawler$.230.parseParams] appium address = Some(http://127.0.0.1:4723/wd/hub)
2019-12-01 21:33:35 INFO [AppCrawler$.242.parseParams] result directory = 20191201213335
2019-12-01 21:33:36 INFO [AppCrawler$.286.parseParams] you can read /Users/qinzhen/Documents/TestDev/AppCrawler/demo.yml for demo
#查看配置文件已生成
$ ls
appcrawler-2.4.0-jar-with-dependencies.jar
demo.yml
- 打開配置文件demo.yaml如下:
---
pluginList: []
saveScreen: true
reportTitle: ""
resultDir: "20191201213335"
waitLoading: 500
waitLaunch: 6000
showCancel: true
maxTime: 10800
maxDepth: 10
capability:
noReset: "true"
fullReset: "false"
appium: "http://127.0.0.1:4723/wd/hub"
testcase:
name: "TesterHome AppCrawler"
steps:
- given: []
when: null
then: []
xpath: "/*"
action: "Thread.sleep(5000)"
actions: []
times: 0
selectedList:
- given: []
when: null
then: []
xpath: "//*[contains(name(), 'Button')]"
action: null
actions: []
times: 0
- given: []
when: null
then: []
xpath: "//*[contains(name(), 'Text') and @clickable='true' and string-length(@text)<10]"
action: null
actions: []
times: 0
- given: []
when: null
then: []
xpath: "//*[@clickable='true']/*[contains(name(), 'Text') and string-length(@text)<10]"
action: null
actions: []
times: 0
- given: []
when: null
then: []
xpath: "//*[contains(name(), 'Image') and @clickable='true']"
action: null
actions: []
times: 0
- given: []
when: null
then: []
xpath: "//*[@clickable='true']/*[contains(name(), 'Image')]"
action: null
actions: []
times: 0
- given: []
when: null
then: []
xpath: "//*[contains(name(), 'Image') and @name!='']"
action: null
actions: []
times: 0
- given: []
when: null
then: []
xpath: "//*[contains(name(), 'Text') and @name!='' and string-length(@label)<10]"
action: null
actions: []
times: 0
firstList: []
lastList:
- given: []
when: null
then: []
xpath: "//*[@selected='true']/..//*"
action: null
actions: []
times: 0
- given: []
when: null
then: []
xpath: "//*[@selected='true']/../..//*"
action: null
actions: []
times: 0
backButton:
- given: []
when: null
then: []
xpath: "Navigate up"
action: null
actions: []
times: 0
triggerActions:
- given: []
when: null
then: []
xpath: "share_comment_guide_btn"
action: null
actions: []
times: 0
xpathAttributes:
- "name"
- "label"
- "value"
- "resource-id"
- "content-desc"
- "instance"
- "text"
sortByAttribute:
- "depth"
- "list"
- "selected"
findBy: "default"
defineUrl: []
baseUrl: []
appWhiteList: []
urlBlackList: []
urlWhiteList: []
blackList:
- given: []
when: null
then: []
xpath: ".*[0-9]{2}.*"
action: null
actions: []
times: 0
beforeRestart: []
beforeElement:
- given: []
when: null
then: []
xpath: "/*"
action: "Thread.sleep(500)"
actions: []
times: 0
afterElement: []
afterPage: []
afterPageMax: 2
tagLimitMax: 2
tagLimit:
- given: []
when: null
then: []
xpath: "確定"
action: null
actions: []
times: 1000
- given: []
when: null
then: []
xpath: "取消"
action: null
actions: []
times: 1000
- given: []
when: null
then: []
xpath: "share_comment_guide_btn_name"
action: null
actions: []
times: 1000
assertGlobal: []
執行參數
同樣,還是以雪球 App 為例,以實際操作運行來解釋配置文件中各個參數的含義和用法
- capability 設置: 與 appium 完全一致,但要注意這里默認有 noReset: "true" 和 appium: "http://127.0.0.1:4723/wd/hub" 屬性,配置完成如下
capability:
noReset: "false"
fullReset: "false"
appium: "http://127.0.0.1:4723/wd/hub"
appPackage: com.xueqiu.androi
appActivity: .view.WelcomeActivityAlias
automationName: uiautomator2
autoGrantPermissions: true
這里再介紹兩個很有趣也很有用的參數:
dontStopAppOnReset: true ;這個參數允許我們在某個頁面繼續執行遍歷,比如我們希望App先進入到某個頁面后再進行遍歷,或者當一個session結束后繼續下一個session的時候我們希望不要殺死App重新執行,而是繼續上一次結束的頁面開始執行
ignoreUnimportantViews: 這個參數設置為true的時候可以忽略不重要的view,加速pageSource的加載,加快測試速度
- testcase: 用於啟動APP后的基礎測試用例

允許我們以 given、when、then 的形式指定操作,如果學習過 Java 的接口自動化框架 rest-assured 話可以很容易理解這三個參數表達的含義:
- given : 所有的先決條件,給定一個條件,只有條件成立的時候才完成后面的操作(實際用的較少)
- when : 先決條件成立后的行為,對什么事件做什么事情
- then : 斷言集合,事件結束后對結果斷言
具體寫法如下:
testcase:
name: "TesterHome AppCrawler"
steps:
- when:
xpath: //*
action: driver.swipe(0.5, 0.8, 0.5, 0.2)
- when:
xpath: //*
action: driver.swipe(0.5, 0.2, 0.5, 0.8)
then:
- //*[contains(@text, '美股')]

另外實際使用中我們會經常使用簡寫形態
- 直接使用 xpath 對應 when 里面的 xpath
- 直接使用 action 對應 when 里面的 action 具體寫法如下:
- xpath: 自選
action: click
then:
- //*[contains(@text, '美股')]

注:定位模式除了可以使用 xpath 之外還可以使用正則和包含關系,只不過經常使用的是 xpath,也更為嚴謹;
- 正則:使用^開頭的就認定為正則,^確定$,^.*輸入密碼
- 包含:可以使用元素其中包含的內容進行定位; 密碼,輸入,請
這里以雪球首頁搜索框輸入 alibaba 的簡單場景舉例,在搜索前還需要處理掉升級彈框,修改完成如下:
testcase:
name: "XueQiuTestDemo AppCrawler"
steps:
- { xpath: "//*[contains(@resource-id,'image_cancel')]", action: click }
- xpath: home_search
action: click
- xpath: search_input_text
action: alibaba
如上的 testcase 寫法還要多說幾句:
- 也可以使用 {} 將需要執行的事件包裹起來,元素定位符和操作 action 時間用逗號隔開
- {} 內若使用 xpath 表達式的話需要加雙引號
- xpath 中直接寫 id 或 text 文本信息,就會默認使用包含去查找
- 需要點擊的事件要明確指明 click,某則會報錯;雖然思寒說過默認的 action 就是 click ,但是經過實測發現在 2.4.0 版本上必須指明 action:click ; 很可能是思寒本地使用的內部版本經過了優化更新還未來得及開源到 GitHub上。
運行效果:

selectedList: 遍歷范圍設定
這里如果想設置讓其點擊所有可點擊的TextView和ImageView控件,修改完成如下:
selectedList:
- xpath: //android.widget.ImageView[@clickable='true']
- xpath: //*[@clickable='true' and contains(@class,"Text")]
- firstList: 優先被點擊
- lastList:最后執行 設置其最后才執行"確定"按鈕,修改完成如下:
lastList:
- { xpath: text_yes, action: click }
- backButton: 當所有元素都被點擊后默認后退控件定位
- blackList:黑名單
- triggerAction: 特定條件出發執行動作的設置;設置遇到重置密碼輸入框時輸入123456abc兩次,修改完成如下:
triggerActions:
- { xpath: android.widget.EditText, action: 123456abc, times: 2 }
- tagLimitMax: 全局設置,同類型的最多點擊的次數;這里設置為2次
tagLimitMax: 2
- tagLimit: 自定義控件類型的點擊次數,這里設置對於ListView類型的只點擊一次; 修改完成如下 :
- { xpath: "//*[contains(@class, 'List')]//*", times: 1 }
- maxDepth: 遍歷的最大深度
assertGlobal:設置一個全局斷言,例如可設置斷言在當前App,如果包名不符合,就可能發生了崩潰,便會報錯
注:執行參數比配置文件優先級高
到這里,appcrawler的基本語法和參數含義大致介紹了一遍,后面就是如何結合實際進行使用了。
(文章來源於霍格沃茲測試學院)