MQC功能測試大揭秘
一、 從Android自動化測試談起
In software testing, test automation is the use of special software (separate from the software being tested) to control the execution of tests and the comparison of actual outcomes with predicted outcomes. Test automation can automate some repetitive but necessary tasks in a formalized testing process already in place, or perform additional testing that would be difficult to do manually. Test automation is critical for continuous delivery and continuous testing. —— wikipedia
維基上對自動化測試的定義簡單來說,就是通過軟件來替代人來執行測試用例,並得到測試結果的過程。當然,對於自動化測試來說,包含的範圍十分大的,對於服務端接口與代碼接口來說,通常采用非Ui自動化的測試方法,如:Unit Test、API Test等等;對於包含Ui元素的完整App、GUI程序來說,Ui自動化的測試方法有:mock、功能測試等等。
對於安卓自動化測試來說,功能測試是最基本也是最常用的方案,那麼功能測試到底能做什麼?有什麼優點?以及如何做好功能測試? MQC 團隊推出係列文章,為大家講解 Appium 技術幹貨以及 MQC 功能測試服務。
維基上對自動化測試的定義簡單來說,就是通過軟件來替代人來執行測試用例,並得到測試結果的過程。當然,對於自動化測試來說,包含的範圍十分大的,對於服務端接口與代碼接口來說,通常采用非Ui自動化的測試方法,如:Unit Test、API Test等等;對於包含Ui元素的完整App、GUI程序來說,Ui自動化的測試方法有:mock、功能測試等等。
功能測試如何幫助改善產品質量
對於大多數敏捷開發團隊來說,要完成對一款大型產品各個方麵進行全方麵的測試是十分困難的。一方麵,我們需要根據每次變更有針對性的測試重點模塊,那麼必然會遺漏對其它模塊的測試;另一方麵,很多模塊的測試工作是機械性的,如回歸測試、性能測試、機型適配等等,全部交給人工測試將大大增加人工成本。
功能測試可以將測試開發從繁瑣的重複勞動中解放出來,把精力集中到重點模塊,同時有餘力設計編寫完善的測試用例,並通過功能測試提高測試覆蓋率,降低隱患。
功能測試的用例不是萬能的
對於測試開發來說,追求100%的測試覆蓋率是無可厚非的,但是事實上很多的測試工作是機器難以完成的,比如文字驗證碼識別。優先設計完成穩定模塊的用例來保證今後功能不斷回歸的工作,之後再考慮時間成本、人力成本的前提下再去考慮更多複雜問題的用例設計。
另一方麵,對於頻繁發生變化的模塊,用例也應當適應這種變化不停迭代,從而快速的在各個機型上進行功能驗證。
功能測試無法發現新問題
我們在編寫和調試用例的時候,或許能夠發現一些功能性問題,而用例在進行回歸後,發現問題的可能性就很低了。功能測試其實就是一個用例不斷重複的過程,功能測試本身應當是一個“守護者”而非“探索者”,它可以幫助我們更加確定應用沒有問題或者發現一些回歸性的問題,而不是新問題。MQC 在探索問題的方向上自主研發了一款兼容性測試工具 Ripper,在達到高覆蓋率的同時保證較高的 Bug 檢出率,有興趣的小夥伴歡迎試用 MQC 兼容性測試。
功能測試是需要成本的
我們通過功能測試用例來保證產品的質量,同時需要專業的工程師來保證用例的質量。設計開發一個合格的用例也是需要不斷的調試、迭代與維護的,這就需要一個好的平台係統來幫助完成相關工作。MQC為開發者提供了完善的用例庫管理功能,同時,為測試開發團隊打造了專業的一站式測試協作平台,幫助團隊進行應用管理、協同工作、任務分發、報告統計。
通過以上幾點內容,相信大家對功能測試的概念已經有了一定的了解。MQC 在 Android 功能測試上選擇使用了 Appium 測試框架,其開源社區較為活躍,兼容性好、功能豐富,相信能滿足絕大部分功能測試的需求;在腳本開發方麵,MQC 提供了在線真機錄製、雲端真機回放等多種服務,來幫助提高用例腳本的開發、調試效率;最後,平台提供了 App 用例管理、用例曆史報告查看、編輯腳本、上傳腳本等功能,幫助用戶通過平台來完成功能測試的迭代維護需求。更多服務,歡迎來阿裏雲移動質量中心進行體驗。
二、Appium環境搭建
這章將會介紹如何搭建與安裝 Appium 的開發環境,主要介紹 Windows 平台的環境搭建,mac 或 linux 需要的相關環境與 Windows 是一樣的,環境搭建本身並不困難,遇到問題大家可以多做嚐試。
相關依賴
Appium 是一款移動端的自動化測試開源工具,Appium 遵循以下4條設計哲學:
- You shouldn’t have to recompile your app or modify it in any way in order to automate it.
- You shouldn’t be locked into a specific language or framework to write and run your tests.
- A mobile automation framework shouldn’t reinvent the wheel when it comes to automation APIs.
- A mobile automation framework should be open source, in spirit and practice as well as in name!
相較於其它的一些功能測試工具,Appium 無需 SDK 或編譯就可以直接對原生應用進行測試;能夠在windows、mac、linux等多種平台運行;能夠支持PHP、Python、Ruby、C#、 Clojure、Java、Objective-C、JavaScript及Perl等等開發語言;能夠同時支持iOS、Android應用的功能測試。因為其強大的功能與便利性,Appium是最活躍的移動測試開源項目之一。
Appium server
Appium 是移動端的測試工具,所以 Android、iOS 的 sdk 是必不可少的。
1.到https://developer.android.com/studio/index.html下載android sdk,若不想下載android studio,可以滑動到最下麵,找到僅獲取命令行工具
2.若要測試iOS應用,推薦安裝 XCode 8 及以上的開發環境。
Appium server 是用 Node.js 編寫的一個服務器。我們可以用源碼編譯或者從 NPM 直接安裝。
1.到Nodejs官網下載最新版本的NodeJs並直接安裝。
2.使用 npm 命令直接安裝 appium 工具
npm install -g appium
通過 npm 安裝 appium 可能遇到一些鏡像地址連接超時、appium啟動權限報錯的問題,同時命令行啟動 appium 時需要添加一些參數, 對於新手,我們更加推薦使用 appium 的桌麵客戶端工具。Appium 桌麵客戶端封裝了運行 Appium 服務端的所有依賴,而不需要擔心怎樣安裝Node.js。其中還包括一個Inspector工具,可以幫助你檢查應用的界麵層級讓你更方便地編寫測試用例。
1.到https://github.com/appium/appium-desktop/releases/tag/v1.2.0-beta.1下載最新的 appium 客戶端。目前 appium-desktop 提供了自動更新的功能,所以不再需要擔心 appium-server 更新的問題了。
2.最新的桌麵客戶端啟動界麵如下,指定 Host 到本地,設定一個空閑的端口(默認 4723)就可以啟動 appium-server了
Appium client
Appium Client 支持絕大部分語言,包括 Java, Ruby, Python, PHP, JavaScript 和 C#,這些庫都實現了 Appium 對 WebDriver 協議的擴展。當使用 Appium 的時候,你隻需使用這些庫代替常規的 WebDriver 庫就可以了。
- java 開發相關依賴可以到 https://github.com/appium/java-client/blob/master/docs/Installing-the-project.md 找到;
- python 開發相關依賴可以到https://pypi.python.org/pypi/Appium-Python-Client進行下載安裝。
好的開始是成功的一半,任何框架都是需要從搭建環境開始做起的,遇到問題多利用各個搜索渠道去解決,相信搭建appium環境一定難不倒大家。
三、Appium基礎篇
上文回顧
上一篇為大家介紹了如何通過appium桌麵客戶端的方式來快速搭建appium環境,桌麵客戶端的appium版本目前為1.6.4,更新稍慢於appium項目,但目前已經支持在線更新,大家不用再有客戶端版本過低的顧慮。
接下來將介紹如何使用python來開發appium功能測試腳本,包括啟動、控件定位、操作、函數封裝、組織用例五個部分。
啟動
Appium啟動時需要指定一些通用配置,統稱為Desired Capabilities,具體的一些參數可以參考Appium服務器初始化參數。這裏介紹一些通用的參數與一些常見的問題。
automationName
自動化測試的引擎,Appium (默認)、Selendroid、Uiautomator2。Appium使用的是UI Automator v1,相比之下UI Automator v2修複了一些v1的bug,在結構上也有一些優化。對於Android7.0以上的係統,UI Automator v1可能在查找控件時出現超時導致appium服務端報錯,這時候可以考慮改用Uiautomator2。
platformName
手機操作係統。
platformVersion
手機操作係統版本。
deviceName
手機類型
app
待測app的路徑
newCommandTimeout
兩條appium命令間的最長時間間隔,若超過這個時間,appium會自動結束並退出app
noReset, fullReset
noReset 不要在會話前重置應用狀態。默認值false。 fullReset (Android) 通過卸載而不是清空數據來重置應用狀態。在Android上, 這也會在會話結束後自動清除被測應用。默認值false。
unicodeKeyboard, resetKeyboard
在輸入的時候,可能出現鍵盤擋住控件的情況,這時候需要使用 appium 提供的輸入法(支持輸入多語言,沒有鍵盤 ui ),unicodeKeyboard 為 true 表示使用 appium-ime 輸入法。 resetKeyboard 表示在測試結束後切回係統輸入法。
appActivity, appPackage
appActivity與appPackage指用於啟動待測app的activityName與packageName,appium(1.6.4)已經支持activityName與packageName的自動檢測,這兩個參數已經可以省略了
appWaitActivity, appWaitPackage
appium需要等待的activityName與packageName,與appActivity不同的是,對於有啟動動畫的app來說,appWaitActivity應該是啟動activity消失後出現的activity。這兩個參數可以指定多個。
有了以上介紹的這些參數,我們可以啟動appium並開始測試app了。將desired capibilities進行封裝,python腳本如下:
from appium import webdriver
def get_desired_capabilities():
desired_caps = {
'platformName': 'Android',
'platformVersion': '18',
'deviceName': 'mqcDevice',
'udid': 'a05aacaf7d53',
'app': "D:\\appium\\alicrowdtest.apk",
'newCommandTimeout': 60,
'automationName': 'appium',
'unicodeKeyboard': True,
'resetKeyboard': True,
'appWaitActivity': 'com.yunos.mqc.view.activity.MainActivity',
}
return desired_caps
def setUp():
# 獲取我們設定的capabilities,通知Appium Server創建相應的會話。
desired_caps = get_desired_capabilities()
# 獲取server的地址。
uri = "https://localhost:4723/wd/hub"
# 創建會話,得到driver對象,driver對象封裝了所有的設備操作。下麵會具體講。
driver = webdriver.Remote(uri, desired_caps)
return driver
if __name__ == '__main__':
driver = setUp()
// 打印當前activity
print driver.current_activity
控件定位
android sdk的tools目錄下自帶一個元素查看工具-uiautomatorviewer,通過這個工具可以獲取到app的各個元素屬性,輔助我們編寫相關的腳本,uiautomatorviewer的界麵如下:
如圖為了定位 尚未登錄 這個控件,我們推薦以下幾種方法:
- xpath: xpath定位效率低,但勝在定位準確,在控件沒有明顯的唯一特征時,xpath的優勢就體現出來了。使用xpath時可以選擇以控件樹的最近公共祖先的節點開始生成查詢路徑。
driver.find_element_by_xpath("//android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.ScrollView[1]/android.widget.LinearLayout[1]/android.widget.RelativeLayout[1]/android.widget.LinearLayout[1]/1android.widget.TextView[1]")
- id: 為了定位方便,開發一般會為部分控件添加resource-id屬性,一般來說可以在一個頁麵中唯一確定一個控件,對於存在多個相同resource-id控件的頁麵,可以通過index來定位這些控件中的某一個
driver.find_element_by_id("com.yunos.mqc:id/user_nickname")
或者
driver.find_elements_by_id("com.yunos.mqc:id/user_nickname")[index]
- text: 定位控件較為簡潔清晰地一種方式,就是通過text來查找控件。
#1.5以上的版本已棄用
driver.find_element_by_name("尚未登錄")
#新版appium使用xpath來實現這個功能
driver.find_element_by_xpath("//*[@text='%s']" % (text))
操作
- swipe: 很多App都會有引導頁需要左滑,這裏提供一個左滑的例子,注意,滑動速度不應太快,否則容易導致引導頁滑動不成功。
window_size = driver.get_window_size()
driver.swipe(start_x=window_size["width"] * 0.9,
start_y=window_size["height"] * 0.5,
end_x=window_size["width"] * 0.1,
end_y=window_size["height"] * 0.5, 500)
- TouchAction: touchaction可以用來實現點擊坐標,滑動等操作,需要注意的是在android係統上,TouchAction的move_to函數是相對坐標。
#點擊操作
TouchAction(driver).press(None, x, y).release().perform()
#滑動操作
TouchAction(driver).press(None, x, y).wait(20).move_to(None, dx, dy).release().perform()
- Scroll: 對於ListView這樣的控件,若要滑動到某個控件位置,按照坐標滑動的方式很難適配不同分辨率的手機,這時候需要考慮使用scroll的方式進行滑動。
#從控件 el1 滑動到 el2
driver.scroll(el1, el2)
- Keyevent: 通過係統按鍵可以實現很多操作,如HOME、POWER、MENU、音量等功能。具體的一些keyevent可以到https://developer.android.google.cn/reference/android/view/KeyEvent.html查看。
#HOME 鍵
driver.keyevent(3)
- long_press: 利用TouchAction,可以實現長按操作:
#長按 el 控件 20s
action = TouchAction(driver)
action.long_press(el, 20000).perform()
sleep(20)
action.release().perform()
- hidekeyboard: 若 desiredcapbility 沒有指定使用 unicodeKeyboard,在輸入的時候需要注意鍵盤 ui 可能會擋住控件的情況,這時候使用 hidekeyboard 函數隱藏鍵盤
# python
driver.hide_keyboard()
函數封裝
在寫腳本的時候,把一些常用的功能合理封裝起來,能夠大大提高腳本執行的成功率。
- 滑動函數: 通過一組坐標點來進行滑動,從而實現一些曲線形的滑動。我們可以實現一個函數用來支持曲線滑動,輸入為形如[[x1, y1],[x2, y2]]的一組坐標點。
def swipe(points):
last_x = 0
last_y = 0
swipe_action = TouchAction(driver)
for i in range(0, len(points)):
x=points[i][0]
y=points[i][1]
if i == 0:
swipe_action = swipe_action.press(None, x, y).wait(20)
elif i == (len(points) - 1):
swipe_action = swipe_action.move_to(None, x - last_x, y - last_y).release()
swipe_action.perform()
else:
swipe_action = swipe_action.move_to(None, x - last_x, y - last_y).wait(20)
last_x = x
last_y = y
- 查找控件: 對於在調試的時候一切順利的腳本,真正到了雲測平台海量真機上測試的時候,卻經常出現控件找不到導致腳本執行失敗的問題。實際真機運行的時候,可能會有很多和本地並不相同的環境情況,比如網絡延遲導致控件較遲刷新出來,我們應當封裝一個較為穩定的控件查找函數。
appium本身有提供waitUntil的api,現在要找圖中的 個人中心 控件,使用顯示等待的方法如下:
from appium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait # available since 2.4.0
from selenium.webdriver.support import expected_conditions as EC
#通過xpath的方式搜索
element1 = WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.XPATH,
"//android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.TabHost[1]/android.widget.LinearLayout[1]/android.widget.TabWidget[1]/android.view.View[4]")))
#通過resource-id的方式搜索,這裏底部導航的resource-id是相同,需要通過下標來區分,搜出多個elements後,需要指定需要的下標
element2 = WebDriverWait(driver, 3).until(EC.presence_of_all_elements_located((By.ID, "com.yunos.mqc:id/id_indicator_discovery")))
element2[3].click()
我們也可以封裝一個多方式定位控件的函數,這裏需要自己把握超時時間
import time
from time import sleep
def wait_for_element(xpath=None, id=None, text=None, index=None, timeout=3):
startTime = time.time()
nowTime = time.time()
while nowTime - startTime < timeout:
# 通過 xpath 查找控件
try:
if xpath is not None:
el = driver.find_element_by_xpath(xpath)
return el
except:
pass
# 通過 id 查找控件
try:
if id is not None:
if index is not None:
return driver.find_elements_by_id(self.id(id))[index]
else:
return driver.find_element_by_id(self.id(id))
except:
pass
# 通過 text 查找控件
try:
if text is not None:
return driver.find_element_by_name(text)
except:
pass
sleep(1)
nowTime = time.time()
raise Exception("Element id[%s] text[%s]" % (id, text))
組織用例
unittest是python的一個單元測試框架,它可以幫助我們有效組織用例,把用例的不同部分區分開來。結合已經封裝好的函數,我們寫一個登錄的測試腳本:
# -*- coding: UTF-8 -*-
import unittest
import time
import sys
from appium import webdriver
from time import sleep
from unittest import TestCase
from appium.webdriver.common.touch_action import TouchAction
from selenium.webdriver.common.touch_actions import TouchActions
class MqcAppium(TestCase):
#設備寬高
global width
global height
def get_desired_capabilities(self):
desired_caps = {
'platformName': 'Android',
'platformVersion': '18',
'deviceName': 'mqcDevice',
'udid': 'a05aacaf7d53',
'app': "D:\\appium\\test.apk",
'newCommandTimeout': 600,
'automationName': 'appium',
'unicodeKeyboard': True,
'resetKeyboard': True,
'appWaitActivity': 'com.yunos.mqc.view.activity.MainActivity',
}
return desired_caps
#unittest 啟動
def setUp(self):
desired_caps = self.get_desired_capabilities()
uri = "https://localhost:4723/wd/hub"
retry = 0
while retry < 2:
try:
self.driver = webdriver.Remote(uri, desired_caps)
break
except Exception, e:
retry += 1
if retry == 2:
raise e
sleep(10)
# 獲取當前設備分辨率
self.window_size = self.driver.get_window_size()
self.width = self.window_size["width"]
self.height = self.window_size["height"]
# unittest 用例,用 test_**** 命名
def test_login(self):
#大部分app啟動後會有動畫,啟動延遲等,視情況預留啟動延遲
sleep(5)
#通過 resource-id 與 index 查找 個人中心 控件
navPerson = self.wait_for_element(, index=3);
navPerson.click()
#通過 text 查找 尚未登錄
noLogin = self.wait_for_element(xpath=("//*[@text='%s']" % ("尚未登錄")));
noLogin.click()
#通過 xpath、resource-id 多種方式定位登錄控件,避免有些手機上 xpath 失效或者不一致的情況
inputUsername = self.wait_for_element(xpath="//android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]\
/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.LinearLayout[1]/android.widget.EditText[1]", )
inputUsername.click()
inputUsername.send_keys("mqc_test")
inputPassword = self.wait_for_element(xpath="//android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/\
android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.LinearLayout[1]/android.widget.EditText[2]", )
inputPassword.click()
inputPassword.send_keys("123456")
login = self.wait_for_element()
login.click()
#返回 廣場 並且向下滑動
navGround = self.wait_for_element(, index=0);
navGround.click()
#與前文 swipe 函數不同的是,為了兼容不同分辨率的手機,滑動操作應當使用 比例 而非 絕對坐標,當然,若是需要精確地滑動操作,建議使用scrollTo
self.swipe([[0.5, 0.7], [0.5, 0.6], [0.5, 0.5], [0.5, 0.4], [0.5, 0.3]])
def tearDown(self):
try:
self.driver.quit()
except:
pass
def swipe(self, points):
last_x = 0
last_y = 0
swipe_action = TouchAction(self.driver)
for i in range(0, len(points)):
x=float(points[i][0]) * self.width
y=float(points[i][1]) * self.height
if i == 0:
swipe_action = swipe_action.press(None, x, y).wait(20)
elif i == (len(points) - 1):
swipe_action = swipe_action.move_to(None, x - last_x, y - last_y).release()
swipe_action.perform()
else:
swipe_action = swipe_action.move_to(None, x - last_x, y - last_y).wait(20)
last_x = x
last_y = y
def wait_for_element(self, xpath=None, id=None, index=None, timeout=3):
startTime = time.time()
nowTime = time.time()
while nowTime - startTime < timeout:
# 通過 xpath 查找控件
try:
if xpath is not None:
el = self.driver.find_element_by_xpath(xpath)
return el
except:
pass
# 通過 id 查找控件
try:
if id is not None:
if index is not None:
return self.driver.find_elements_by_id(id)[index]
else:
return self.driver.find_element_by_id(id)
except:
pass
sleep(1)
nowTime = time.time()
raise Exception("Element xpath[%s] id[%s] index[%s] not found" % (xpath, id, index))
if __name__ == '__main__':
try: unittest.main()
except SystemExit: pass
四、MQC 功能測試 DEMO
MQC為大家提供了海量的適配真機、強大的在線錄製、遍曆的用例管理、定製化的報告展示等功能,這篇文章將會通過一個 DEMO 教會大家如何利用好 MQC 提供的這些服務來回歸測試自己的 App。
如何使用 MQC 功能測試服務?
Appium 基礎篇有提到,desired capabilities 會提供 appium 運行時的各項環境參數,MQC 在功能測試開始前會動態生成desired capabilities類,用戶腳本隻需要調用相關 api 即可快速啟動 Appium。
import desired_capabilities
def setUp():
desired_caps = desired_capabilities.get_desired_capabilities()
uri = desired_capabilities.get_uri()
driver = webdriver.Remote(uri, desired_caps)
除此之外,MQC 提供了許多定製化的操作,隻需要按照格式進行簡單的 log 打印,就可以實現記錄步驟、截圖、記錄執行狀態等等操作,使得報告更加完善。當然,不打日誌同樣可以使用功能測試服務,隻需要上傳一個可執行的 main.py 文件(打包成zip文件)。
# 步驟1: 等待5s
print "STEP : 等待5s"
# 判斷該步驟執行狀態,FATAL : exception, 表示該步驟失敗; ASSERT : true, 表示該步驟成功; ASSERT : false, 表示該步驟失敗且該用例也失敗
print "FATAL : element not found"
# 為該步驟截圖
print "SCREENSHOT : 1"
一個合理且容易被解析的日誌結構應該如下:
STEP : 等待5s
SCREENSHOT : 0
STEP : 點擊控件:com.hexin.plat.android.ShenWanHongYuanSecurity:id/launch_ad
FATAL : element not found
SCREENSHOT : 1
STEP : 等待5s
SCREENSHOT : 2
STEP : 點擊控件:請輸入您有效的手機號
ASSERT : true
SCREENSHOT : 3
那麼,我們可以把上篇文章的 DEMO 進行改造,腳本如下:
# -*- coding: UTF-8 -*-
import unittest
import time
import sys
from appium import webdriver
from time import sleep
from unittest import TestCase
from appium.webdriver.common.touch_action import TouchAction
from selenium.webdriver.common.touch_actions import TouchActions
class MqcAppium(TestCase):
#設備寬高
global width
global height
#unittest 啟動
def setUp(self):
desired_caps = self.get_desired_capabilities()
uri = "https://localhost:4723/wd/hub"
retry = 0
while retry < 2:
try:
self.driver = webdriver.Remote(uri, desired_caps)
break
except Exception, e:
retry += 1
if retry == 2:
raise e
sleep(10)
# 獲取當前設備分辨率
self.window_size = self.driver.get_window_size()
self.width = self.window_size["width"]
self.height = self.window_size["height"]
# unittest 用例,用 test_**** 命名
def test_login(self):
#大部分app啟動後會有動畫,啟動延遲等,視情況預留啟動延遲
sleep(5)
#通過 resource-id 與 index 查找 個人中心 控件
navPerson = self.wait_for_element(, index=3);
navPerson.click()
#通過 text 查找 尚未登錄
noLogin = self.wait_for_element(xpath=("//*[@text='%s']" % ("尚未登錄")));
noLogin.click()
#通過 xpath、resource-id 多種方式定位登錄控件,避免有些手機上 xpath 失效或者不一致的情況
inputUsername = self.wait_for_element(xpath="//android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]\
/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.LinearLayout[1]/android.widget.EditText[1]", )
inputUsername.click()
inputUsername.send_keys("mqc_test")
inputPassword = self.wait_for_element(xpath="//android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/\
android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.LinearLayout[1]/android.widget.EditText[2]", )
inputPassword.click()
inputPassword.send_keys("123456")
login = self.wait_for_element()
login.click()
#返回 廣場 並且向下滑動
navGround = self.wait_for_element(, index=0);
navGround.click()
#與前文 swipe 函數不同的是,為了兼容不同分辨率的手機,滑動操作應當使用 比例 而非 絕對坐標,當然,若是需要精確地滑動操作,建議使用scrollTo
self.swipe([[0.5, 0.7], [0.5, 0.6], [0.5, 0.5], [0.5, 0.4], [0.5, 0.3]])
def tearDown(self):
try:
self.driver.quit()
except:
pass
def swipe(self, points):
last_x = 0
last_y = 0
swipe_action = TouchAction(self.driver)
for i in range(0, len(points)):
x=float(points[i][0]) * self.width
y=float(points[i][1]) * self.height
if i == 0:
swipe_action = swipe_action.press(None, x, y).wait(20)
elif i == (len(points) - 1):
swipe_action = swipe_action.move_to(None, x - last_x, y - last_y).release()
swipe_action.perform()
else:
swipe_action = swipe_action.move_to(None, x - last_x, y - last_y).wait(20)
last_x = x
last_y = y
def wait_for_element(self, xpath=None, id=None, index=None, timeout=3):
startTime = time.time()
nowTime = time.time()
while nowTime - startTime < timeout:
# 通過 xpath 查找控件
try:
if xpath is not None:
el = self.driver.find_element_by_xpath(xpath)
return el
except:
pass
# 通過 id 查找控件
try:
if id is not None:
if index is not None:
return self.driver.find_elements_by_id(id)[index]
else:
return self.driver.find_element_by_id(id)
except:
pass
sleep(1)
nowTime = time.time()
raise Exception("Element xpath[%s] id[%s] index[%s] not found" % (xpath, id, index))
if __name__ == '__main__':
try: unittest.main()
except SystemExit: pass
準備好腳本後,就可以到 MQC 平台進行提測了:
1.將這個腳本打包成zip包,到 MQC主頁 添加待測app, 之後進入用例庫頁麵
2.創建一個新用例,取名為 登錄
3.進入功能測試提測頁麵進行用例提測, 用戶自己上傳腳本創建用例需選中已上傳用例,使用在線錄製服務創建的用例需選擇已錄製用例
4.將上麵的 DEMO 腳本提測後,24小時內便可查看測試報告。
怎麼使用在線錄製?
大家寫功能測試腳本的時候一定有想過錄製回放這樣的功能,就是通過工具把操作錄製下來,而後再通過引擎回放錄製的動作。在線錄製結合了雲真機機型多的優勢,提供了這麼一項在線服務。在線錄製可以大大加速用例的生成,但是,一個好的用例是需要不斷地驗證打磨的,除了基本的點擊、滑動操作外,若您有具體的功能驗證需求,如圖片上傳、隨機密碼鍵盤等等,都是需要有經驗的工程師來修改完善腳本的, 在線錄製僅僅是用例腳本設計中的第一步。當然,若您有複雜的用例設計需求,也可以聯係我們,通過在阿裏雲購買人工支持用例設計,讓阿裏雲的測試專家為您的 app 量身定製用例。
在使用在線錄製的時候,可以看到下圖所示界麵
1.在點擊的時候若出現控件樹不準確的情況,需要手動點擊刷新(框1)來重新解析控件樹;
2.框2中的內容是控件的坐標、resource-id[index]、text信息;
3.有些 app 有左滑的起始頁,這裏封裝了一些滑動操作,可以有效避免錄製的左滑動作過快或過短導致回放失敗的問題;對於一些輸入操作,錄製時直接使用鍵盤輸入可能沒有準確識別出該步所有輸入文本,可以使用 輸入 按鈕來完成輸入的操作;
4.框4和框5是直接使用在線錄製回放腳本,可以快速驗證錄製腳本的準確性,框4能夠直接支持單步回放,框5可以構建appium腳本再使用appium引擎進行回放。
更多功能
MQC 提供了完善的測試流程管理功能,覆蓋測試的整個生命周期,除了在線錄製、真機回放、測試任務管理等,還有用例庫管理、App版本管理、App缺陷統計等等功能,歡迎大家來使用體驗,這裏重點介紹用例庫的參數管理。
大家在寫功能測試腳本的時候可能都用過excel來管理一些常量,並在測試的時候傳遞給測試用例,這些通常會是腳本裏的參數。在使用雲端真機進行測試的時候,可以通過參數管理功能來完成參數的分發、互踢等工作,直接在腳本中獲取參數,同時在線維護參數值。
如下圖創建兩組參數 username、password、point,在提測時選上使用的參數,平台會自動將參數分發到各個功能測試任務並執行
同樣,使用 desired_capabilities 類可以獲取到相應的參數:
import desired_capabilities
username = desired_capabilities.getParam("username")
password = desired_capabilities.getParam("password")
point = desired_capabilities.getParam("point")
到這 appium 功能測試的一些基本概念與服務已經介紹完全了,後續 MQC 會繼續和大家分享功能測試的一些專業知識,希望大家持續關注。
上文提到的移動測試產品詳情,請見https://www.aliyun.com/product/mqc
最後更新:2017-09-20 10:32:50