本文檔將詳細介紹如何搭建 Appium 的運行環境,以及如何編寫一個簡單的 UI 自動化測試用例。其中,也會穿插講解一些 Appium 的基本知識。關於 Appium 的更多信息,大家可以查看官方文檔。
注意事項:
- 本文檔是在 macOS 系統的基礎上講解相關操作
- 編程語言選擇了:Python 2.7
- Appium 是跨平台的 UI 自動化測試框架,支持 Android、iOS 等系統,本次只介紹基於 Android 的自動化測試
安裝 Appium
Appium 的安裝有兩種方式:
1、下載 Appium Desktop,這個是 Appium 的客戶端軟件,包含了運行 Appium 所需要的一切,下載后安裝即可,支持 Mac、Windows、Linux 三大系統。因為安裝過程實在是太簡單了,所以不做詳細說明。
2、通過命令行的方式進行安裝,這個比較復雜,需要依次下載安裝多種配置/依賴來滿足 Appium 的運行條件。着重介紹此種安裝方式。
命令行安裝
以下命令都是在終端(Terminal)上運行的
1、安裝包管理工具 Homebrew
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
2、安裝 Node.js
brew install node
3、安裝 Appium 服務端
npm install -g appium
4、安裝 appium-doctor
npm install -g appium-doctor
5、運行 appium-doctor,檢查 Appium 需要的所有依賴是否都滿足
appium-doctor --android
其中有幾個依賴項是必須要滿足的:
- Node.js
- ANDROID_HOME
- JAVA_HOME
- adb
- android
- emulator
- $JAVA_HOME/bin
大家可根據這個命令運行結束后的提示信息去完成相應的依賴添加:
6、安裝 Appium 客戶端
pip install Appium-Python-Client
7、最后,因為需要使用 Python 語言編寫自動化測試用例,建議安裝 Python 語言的 IDE:PyCharm
腳本編寫
腳本編寫前的准備工作
1、啟動 Appium
(1)如果安裝了 Appium Desktop,可直接打開軟件點擊 "Start" 啟動 Appium 服務
(2)如果是通過命令行方式安裝的 Appium,則在終端(Terminal)輸入:
appium
2、啟動模擬器/測試設備連接至電腦
#啟動模擬器
emulator @<emulator_name>
#測試設備連接至電腦
(1)Settings-Developer options-USB debugging //打開usb調試模式
(2)adb devices //查看手機是否成功連接至電腦
3、安裝待測應用到模擬器/測試設備中
adb install <path_to_apk>
本次講解計算器應用 iClever Calculator Lite 為例,可自行到 Google Play 上下載該應用,包名為:weightloss.constellation.education.tools
創建腳本
在完成以上三步后,打開 Pycharm 或者其他 IDE,新建一個 py 文件,完成自動化測試腳本基礎代碼的編寫。
1、新建 calculator_test.py 文件
2、導入類庫和包
#導入unittest測試框架
import unittest
#導入appium客戶端庫
from appium import webdriver
#導入time模塊
from time import sleep
3、創建一個類 CalculatorTest,繼承自 Python 的測試類 unittest.TestCase
class CalculatorTest(unittest.TestCase):
pass
unittest 是 Python 的一個單元測試框架,包含了四個部分:
- TestFixture
- setUp
- TestCase
- TearDown
- TestCase
- TestSuite
- TestRunner
關於各部分的概念和應用,在下面章節里說明(參見代碼注釋)。
4、在類中創建三個方法:setUP()、tearDown()、test_case_1(),然后在類外面創建一個程序入口
class CalculatorTest(unittest.TestCase):
# pass
#SetUP,case運行前的環境初始化
def setUp(self):
pass
#TearDown,case運行后的環境恢復
def tearDown(self):
pass
#TestCase,測試用例1
def test_case_1(self):
pass
#程序入口
if __name__ == '__main__':
#TestSuite,將所有測試用例載入suite
suite = unittest.TestLoader().loadTestsFromTestCase(CalculatorTest)
#TestRunner,運行測試用例
unittest.TextTestRunner(verbosity=2).run(suite)
5、在 setUP() 中添加字典變量 desired_caps,初始化配置,提供建立 Session 所需要的信息
#SetUP,case運行前的環境初始化
def setUp(self):
# pass
#字典變量,初始化配置,提供建立session的所有必要信息:http://appium.io/docs/en/writing-running-appium/caps/index.html
desired_caps = {}
#被測應用平台:iOS/Android
desired_caps['platformName'] = 'Android'
#被測應用平台版本:adb shell getprop ro.build.version.release
desired_caps['platformVersion'] = '8.0.0'
#測試設備名:adb devices
desired_caps['deviceName'] = 'CB512FCM14'
#被測應用包名
desired_caps['appPackage'] = 'weightloss.constellation.education.tools'
#被測應用啟動時的活動名
desired_caps['appActivity'] = 'com.weightloss.constellation.education.tools.SplashActivityAlias'
#服務端等待客戶端發送消息的超時時間
desired_caps['newCommandTimeout'] = 150
#在一個session開始前不重置被測程序的狀態
desired_caps['noReset'] = True
#是否支持uicode的鍵盤(輸入中文需設置)
desired_caps['unicodeKeyboard'] = True
#以desired_caps作為參數初始化WebDriver連接
#Appium服務器的IP:http://localhost
#端口號:4723
self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
sleep(10)
其中,有兩個變量 "platformVersion" 和 "deviceName" 需要大家自行修改,可通過以下命令獲取測試設備系統版本號和設備名
adb shell getprop ro.build.version.release //獲取測試設備系統版本號
adb devices //獲取設備名
6、在 tearDown() 中調用 quit(),退出driver,關閉被測應用所有的關聯窗口
#TearDown,case運行后的環境恢復
def tearDown(self):
# pass
#退出driver,關閉被測應用所有的關聯窗口
self.driver.quit()
7、至此,一個基礎的 Appium 自動化測試腳本已編寫完成。通過終端(Terminal)進入腳本所在的目錄,輸入以下語句運行腳本
python calculator_test.py
自動化測試用例的編寫
在完成上述步驟后,一個基礎的自動化測試腳本便生成了。接下來,具體講解如何編寫 case。
case 的編寫,簡而言之有三步:
- 1.動作執行
- 查找和識別元素
- 操作元素
- 2.結果判斷
- 3.報告展示
動作執行
查找和識別元素
元素,在這里指的是應用程序用戶界面上的控件。可以通過谷歌官方提供的工具 uiautomatorviewer 進行查找和識別。
1、進入 Android SDK 的 bin 目錄
cd ${ANDROID_HOME}/tools/bin //每個人的Android sdk的目錄名不一樣哦
2、啟動 uiautomatorviewer
uiautomatorviewer
3、在測試設備上啟動應用,進入需要識別和操作的用戶界面。在 uiautomatorviewer 上,點擊左上角第二個按鈕"Device Screenshot(uiautomator dump)",對當前界面上的元素進行查找和識別
4、在獲取到界面上元素的布局層級及其屬性后,可以通過如下一些方法進行元素的識別
- find_element_by_id---對應組件屬性中的"resource_id"
- find_element_by_class_name---對應組件屬性中的"class"
- find_element_by_name---對應組件屬性中的"text"
- find_element_by_accessibility_id---對應組件屬性中的"content-desc"
更多方法,請查看 Appium 的官方文檔
http://appium.io/docs/en/writing-running-appium/finding-elements/
http://appium.io/docs/en/commands/element/find-elements/index.html#selector-strategies
https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md
http://appium.io/docs/en/writing-running-appium/android/uiautomator-uiselector/index.html
操作元素
元素操作的方法,分為三種:
-
- text(self)---獲取文本信息
- click(self)---點擊
- clear(self)---清空文本
- is_enabled(self)---是否可用
- is_selected(self)---是否已選
- is_displayed(self)---是否顯示
- send_keys(self, *value)---模擬輸入文本
-
- tap(self, positions, duration=None)---點擊,自定義坐標
- swipe(self, start_x, start_y, end_x, end_y, duration=None)---滑動
- flick(self, start_x, start_y, end_x, end_y)---快速滑動
- pinch(self, element=None, percent=200, steps=50)---縮小
- zoom(self, element=None, percent=200, steps=50)---放大
- scroll(self, origin_el, destination_el)---滾動
- drag_and_drop(self, origin_el, destination_el)---拖曳
-
- press_keycode()---模擬按鍵
- long_press_keycode()---模擬長按鍵
- reset()---重置程序到初始狀態
- pull_file()---從手機上拉取文件
- launch_app()---啟動應用程序
- start_activity()---啟動活動
- shake()---晃動手機
- get_screenshot_as_file()---獲取截圖並保存在電腦上
- push_file()---推送文件到手機
更多操作元素的方法,請查看 Appium 的官方文檔
本次實例,以 iClever Calculator Lite 為被測應用,創建一個 test_plus() 方法,查找和識別以及操作元素
def test_plus(self):
#預期結果等於10
result = 10
#通過ID找到7
seven = self.driver.find_element_by_id("weightloss.constellation.education.tools:id/button_7")
#通過ID找到3
three = self.driver.find_element_by_id("weightloss.constellation.education.tools:id/button_3")
#通過ID找到+
plus = self.driver.find_element_by_id("weightloss.constellation.education.tools:id/button_plus")
#通過ID找到=
equal = self.driver.find_element_by_id("weightloss.constellation.education.tools:id/button_equal")
#通過ID找到結果
real_result = self.driver.find_element_by_id("weightloss.constellation.education.tools:id/display")
#點擊7
seven.click()
#點擊+
plus.click()
#點擊3
three.click()
#點擊=
equal.click()
結果判斷
在找到元素並對元素進行相應操作后,需要確認結果是否符合預期
結果判斷有兩種方式:
- 斷言
- assertEqual(a, b)---判斷a==b
- assertNotEqual(a, b)---判斷a!=b
- assertTrue(x)---bool(x) is True
- assertFalse(x)---bool(x) is False
- 截圖對比
- get_screenshot_as_file(self, filename)
- save_screenshot(self, filename)
- get_screenshot_as_png(self)
- get_screenshot_as_base64(self)
在 test_plus() 里添加斷言和截圖:
def test_plus(self):
#預期結果等於10
result = "10"
#通過ID找到7
seven = self.driver.find_element_by_id("weightloss.constellation.education.tools:id/button_7")
#通過ID找到3
three = self.driver.find_element_by_id("weightloss.constellation.education.tools:id/button_3")
#通過ID找到+
plus = self.driver.find_element_by_id("weightloss.constellation.education.tools:id/button_plus")
#通過ID找到=
equal = self.driver.find_element_by_id("weightloss.constellation.education.tools:id/button_equal")
#通過ID找到結果
real_result = self.driver.find_element_by_id("weightloss.constellation.education.tools:id/display")
#點擊7
seven.click()
#點擊+
plus.click()
#點擊3
three.click()
#點擊=
equal.click()
#斷言結果是否相等
self.assertEqual(real_result.text, result)
#截圖
self.driver.get_screenshot_as_file(self.SCREEN_SHOT_PATH + "plus_result.png")
報告展示
當運行完所有的 test case 后,如何以直觀的形式展示結果?
Github 上有一個開源項目---HtmlTestRunner,能夠以 HTML 的形式輸出報告。
1、安裝 HtmlTestRunner
pip install html-testRunner
2、導入 HtmlTestRunner 模塊,使用 HTMLTestRunner 替換 unittest.TextTestRunner
#導入HtmlTestRunner
import HtmlTestRunner
...
#程序入口
if __name__ == '__main__':
#TestSuite,將所有測試用例載入suite
suite = unittest.TestLoader().loadTestsFromTestCase(CalculatorTest)
#TestRunner,運行測試用例
# unittest.TextTestRunner(verbosity=2).run(suite)
#運行case+輸出報告
runner = HtmlTestRunner.HTMLTestRunner(output='cc_report')
runner.run(suite)
示例:
附上完整的代碼:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author : Shengjie.Liu
# @Time : 2019-06-03 14:47
# @File : calculator_test.py
# @Desc :
#導入unittest測試框架
import unittest
#導入appium客戶端庫
from appium import webdriver
#導入time模塊
from time import sleep
#導入HtmlTestRunner
import HtmlTestRunner
class CalculatorTest(unittest.TestCase):
# pass
# 截圖路徑
SCREEN_SHOT_PATH = "/Users/liushengjie/PycharmProjects/AppiumTest/share/"
#SetUP,case運行前的環境初始化
def setUp(self):
# pass
#字典變量,初始化配置,提供建立session的所有必要信息:http://appium.io/docs/en/writing-running-appium/caps/index.html
desired_caps = {}
#被測應用平台:iOS/Android
desired_caps['platformName'] = 'Android'
#被測應用平台版本:adb shell getprop ro.build.version.release
desired_caps['platformVersion'] = '8.0.0'
#測試設備名:adb devices
desired_caps['deviceName'] = 'CB512FCM14'
#被測應用包名
desired_caps['appPackage'] = 'weightloss.constellation.education.tools'
#被測應用啟動時的活動名
desired_caps['appActivity'] = 'com.weightloss.constellation.education.tools.SplashActivityAlias'
#服務端等待客戶端發送消息的超時時間
desired_caps['newCommandTimeout'] = 150
#在一個session開始前不重置被測程序的狀態
desired_caps['noReset'] = True
#是否支持uicode的鍵盤(輸入中文需設置)
desired_caps['unicodeKeyboard'] = True
#以desired_caps作為參數初始化WebDriver連接
#Appium服務器的IP:http://localhost
#端口號:4723
self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
sleep(10)
#TearDown,case運行后的環境恢復
def tearDown(self):
# pass
#退出driver,關閉被測應用所有的關聯窗口
self.driver.quit()
#TestCase,測試用例1
def test_case_1(self):
pass
def test_plus(self):
#預期結果等於10
result = "10"
#通過ID找到7
seven = self.driver.find_element_by_id("weightloss.constellation.education.tools:id/button_7")
#通過ID找到3
three = self.driver.find_element_by_id("weightloss.constellation.education.tools:id/button_3")
#通過ID找到+
plus = self.driver.find_element_by_id("weightloss.constellation.education.tools:id/button_plus")
#通過ID找到=
equal = self.driver.find_element_by_id("weightloss.constellation.education.tools:id/button_equal")
#通過ID找到結果
real_result = self.driver.find_element_by_id("weightloss.constellation.education.tools:id/display")
#點擊7
seven.click()
#點擊+
plus.click()
#點擊3
three.click()
#點擊=
equal.click()
#斷言結果是否相等
self.assertEqual(real_result.text, result)
#截圖
self.driver.get_screenshot_as_file(self.SCREEN_SHOT_PATH + "plus_result.png")
#程序入口
if __name__ == '__main__':
#TestSuite,將所有測試用例載入suite
suite = unittest.TestLoader().loadTestsFromTestCase(CalculatorTest)
#TestRunner,運行測試用例
# unittest.TextTestRunner(verbosity=2).run(suite)
#運行case+輸出報告
runner = HtmlTestRunner.HTMLTestRunner(output='cc_report')
runner.run(suite)
此份文檔僅做拋磚引玉之用,希望同學們可以根據此文檔完成第一個 UI 自動化測試用例。至於之后的編寫,需要大家勤查資料,多看官網。