本文為霍格沃茲測試開發學社學員學習筆記分享
原文連結:使用者端app自動化測試1 - 學習筆記 - 測試人社群
App 自動化測試的價值與體系
- 提高效率
- 融入企業疊代流水線,與 CI/CD/DevOps 結合
- 回歸測試、功能測試加速
- 提高品質:
- 相容性測試
- 專項/非功能測試
- 自動化探索測試
UI 自動化測試用例如何編寫
- 業務流程不頻繁改動
- UI 元素不頻繁改動
- 需要頻繁回歸的場景
- 核心場景等
環境安裝與使用
什麼是appium
- Client/Server Architecture:c/s 架構
- 腳本多語言支援
- Java、Python、ruby、PHP、JavaScript、C#
- 生态豐富,社群強大
Android 指令行工具
- 管理移動端裝置上應用程式的安裝與解除安裝,以及檢視相關資訊
- adb
- 安卓系統的指令行控制工具
- 擷取安卓端的各種資料和控制
- sdk 自帶工具
adb devices #顯示目前所連接配接裝置的udid
iOS 指令行工具
- ideviceinstaller
- iOS 系統的指令行控制工具
- 擷取 iOS 端的各種資料和控制
idevice_id -l #顯示目前所連接配接裝置的 udid
Appium Desktop
- 内嵌了 Appium Server
- Appium Server GUI
- Appium 核心工具,指令行工具
- Appium Inspector
- 1.22 版本後,和 desktop 分開
Appium Client
- 各種語言的用戶端封裝庫、用于連接配接 Appium Server
capability 配置參數解析
簡介:
- 功能:配置 Appium 會話,告訴 Appium 伺服器需要自動化的平台的應用程式
- 形式:鍵值對的集合,鍵對應設定的名稱,值對應設定的值
- 主要分為三部分
- 公共部分
- ios 部分
- android 部分
Session:
- Appium 的用戶端和服務端之間進行通信的前提
- 通過 Desired Capabilities 建立會話
配置優化
- 添加參數,提高用例的穩定性
{
"noReset": "true", // 不清空緩存資訊
"dontStopAppOnReset": "true", // 首次啟動的時候,不停止app
"skipDeviceInitialization": "true", // 跳過安裝,權限設定等操作
"unicodeKeyBoard": "true" // 輸入中文
}
app 自動化控制
- 啟動應用
- 方式一:webdriver.remote("url",desirecapability)
- 方式二:launch_app() 将應用啟動起來
# 方式一:
self.driver = webdriver.Remote\
("http://127.0.0.1:4723/wd/hub", desire_cap)
# 方式二:
self.driver.launch_app()
- 清空輸入框内容 clear()
self.driver.find_element_by_accessibility_id('SomeAccessibilityID').clear()
- 關閉 quit()
self.driver.quit()
常見控件定位方法
android 基礎知識
- Android 是通過容器的布局屬性來管理子控件的位置關系,布局關系就是把界面上的所有的空間,根據他們的間距的大小,擺放在正确的位置
- Android 七大布局
- LinerLayout(線性布局)
- RelativeLayout(相對布局)
- FrameLayout(幀布局)
- AboluteLayout(絕對布局)
- TableLayout(表格布局)
- GridLayout(網格布局)
- ConstraintLayout(限制布局)
- Android 四大元件
- activity 與使用者互動的可視化界面
- service 實作程式背景運作的解決方案
- content provider 内容提供者,提供程式所需要的資料
- broadcast receiver 廣播接收器,監聽外部事件的到來(比如來電)
- 常用的控件
- TextView(文本控件),EditText(可編輯文本控件)
- Button(按鈕),ImageButton(圖檔按鈕),ToggleButton(開關按鈕)
- ImageView(圖檔控件)
- CheckBox(複選框控件),RadioButton(單選框控件)
- 布局
- 是可用于放置很多控件的容器按照一定的規律調整内部控件的位置由此構成界面。
- 嵌套布局
- 布局内部放置布局,多層布局嵌套,可以完成複雜的界面結構
iOS 與 Android dom 結構的差別
- dom 屬性和節點結構類似
- 名字和屬性命名不同
- android 的 resourceid 和 ios 的 name
- android 的 content-desc 和 ios 的 accessibility-id
定位方法
- 測試步驟三要素
- 定位、互動、斷言
- 定位方式:
- id 定位
- accessibilty_id 定位
- xpath 定位
- classname 定位(不推薦)
元素定位的寫法
- 傳回單個元素 WebElement
- 傳回元素清單 [WebElement, WebElement, WebElement…]
# 傳回單個元素 WebElement
driver.find_element(AppiumBy.xxx, "xxx屬性值")
# 傳回元素清單 [WebElement, WebElement, WebElement...]
driver.find_elements(AppiumBy.xxx, "xxx屬性值")
元素定位的寫法
driver.find_element(AppiumBy.ID, "ID屬性值")
driver.find_element(AppiumBy.XPATH, "xpath表達式")
driver.find_element(AppiumBy.CLASS_NAME, "CLASS屬性值")
driver.find_element(AppiumBy.ACCESSIBILITY_ID, "ACCESSIBILITY_ID表達式")
driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, "android uiautomator 表達式")
driver.find_element(AppiumBy.IOS_UIAUTOMATION, "ios uiautomation 表達式")
driver.find_element(AppiumBy.ANDROID_VIEWTAG, "ESPRESSO viewtag 表達式")
driver.find_element(AppiumBy.ANDROID_DATA_MATCHER, "ESPRESSO data matcher 表達式")
driver.find_element(AppiumBy.IMAGE, "IMAGE圖檔")
ID 定位
- 通過身份辨別 id 查找元素
- 寫法:find_element(AppiumBy.ID, "ID屬性值")
ACCESSIBILITY_ID 定位
- 通過 accessibility id 查找元素
- 寫法:find_element(AppiumBy.ACCESSIBILITY_ID, "ACCESSIBILITY_ID屬性值")
XPath 單屬性定位
- 基本表達式://*[@屬性名='屬性值']
XPath 多屬性定位
- 表達式://*[@屬性名='屬性值' and @屬性名='屬性值' ]
Android 原生定位
- 元素屬性定位
- ID 定位
- 文本定位
- 文本比對定位
- 父子關系定位
- 兄弟關系定位
Android 原生定位 - 單屬性定位
- 格式 'new UiSelector().屬性名("<屬性值>")'
- 比如:'new UiSelector().resourceId("android:id/text1")'
- 注意外面是單引号,裡面是雙引号,順序不能變
- 可以簡寫為 屬性名("<屬性值>")'
- 比如:·resourceId("android:id/text1")
# ID 定位
def test_android_uiautomator_by_id(self):
print(self.driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR,\
'new UiSelector().resourceId("android:id/text1")'))
# TEXT 定位
def test_android_uiautomator_by_text(self):
print(self.driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR,\
'new UiSelector().text("App")'))
# classname 定位
def test_android_uiautomator_by_className(self):
print(self.driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, \
'new UiSelector().className("android.widget.TextView")'))
Android 原生定位-組合定位
多個屬性同時确定元素的(多個屬性任意組合 ,不限長度)
driver.find_element_by_android_uiautomator('\
new UiSelector().resourceId("com.xueqiu.android:id/tab_name").\
text("我的")')
Android 原生定位-模糊比對
文字包含
文字以 x 開頭
文字正則比對
# 模糊比對
def test_android_uiautomator_by_text_contains(self):
print(self.driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().textContains("ssi")').text)
def test_android_uiautomator_by_text_start_with(self):
print(self.driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().textStartsWith("Ani")').text)
def test_android_uiautomator_by_text_match(self):
print(self.driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().textMatches("^Pre.*")').text)
Android 原生定位-層級定位
兄弟元素定位 fromParent
父子結點定位 childSelector, 可以傳入 resourceId() , description() 等方法
# 查找目标元素Text,先找App ,fromParent() 方法可以查找兄弟結點
new UiSelector().text("App").fromParent(text("Text"))
# 根據父結點查找子結點/ 子孫結點
new UiSelector().className("android.widget.ListView").childSelector(text("Text"))
滑動查找元素
new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("查找的元素文本").instance(0))
Android 原生定位-組合定位
- 多個屬性同時确定元素的(多個屬性任意組合 ,不限長度)
driver.find_element_by_android_uiautomator('\
new UiSelector().resourceId("com.xueqiu.android:id/tab_name").\
text("我的")')
Android 原生定位-模糊比對
- 文字包含
- 文字以 x 開頭
- 文字正則比對
Android 原生定位-層級定位
- 兄弟元素定位 fromParent
- 父子結點定位 childSelector, 可以傳入 resourceId() , description() 等方法
滑動查找元素
new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().t