銀川網(wǎng)站建設(shè)設(shè)計(jì)短視頻如何引流與推廣
1. 目的
相信做過測試的同學(xué)都聽說過自動(dòng)化測試,而UI自動(dòng)化無論何時(shí)對測試來說都是比較吸引人的存在。相較于接口自動(dòng)化來說,它可以最大程度的模擬真實(shí)用戶的日常操作與特定業(yè)務(wù)場景的模擬,那么存在即合理,自動(dòng)化UI測試自然也是廣大測試同學(xué)職業(yè)道路上必不可少的必修課題之一了。
2. 意義
說到UI自動(dòng)化,不同的公司、不同的團(tuán)隊(duì)往往看待它的態(tài)度也存在著很大的差異。項(xiàng)目或產(chǎn)品是否值得做UI自動(dòng)化?執(zhí)行的方向是否正確?落地的成本是否過大?大部分的測試團(tuán)隊(duì)都會(huì)有同樣的疑問,不管初衷如何,(KPI? 晉升?內(nèi)部推廣?效率優(yōu)化?)最大的難點(diǎn)一般都在于落地后如何保持一個(gè)穩(wěn)定的使用周期與實(shí)際維護(hù)的成本是否小于團(tuán)隊(duì)投入期望值,說人話就是用來UI自動(dòng)化之后是否大家都能用且可以長久的持續(xù)與維護(hù)下去。
這里博主建議的是,在做UI自動(dòng)化之前先想清楚動(dòng)機(jī)是什么,如果真的只是自我拓展、KPI或者個(gè)人成果展示,那就掌握掌握原理與實(shí)操一下即可,沒有必要在團(tuán)隊(duì)內(nèi)進(jìn)行推廣;如果真的是解決團(tuán)隊(duì)的實(shí)際需求:歷次回歸都需大量的手工,每次右移后需要全功能回歸,功能數(shù)量大、場景多、功能增量后耦合較低的情況,則可以簡單的評估一下引入自動(dòng)化UI測試預(yù)計(jì)帶來的成果與提升效果。
3. 設(shè)計(jì)理念
之所以選用PO模式,也正是因?yàn)橐话愕腁PP項(xiàng)目或產(chǎn)品功能都是增量式迭代開發(fā)的,那么必定會(huì)面臨需要維護(hù)的功能頁面越來越多的處境。如果是傳統(tǒng)的設(shè)計(jì)模式,頁面的元素與業(yè)務(wù)的操作會(huì)全部放在一個(gè)腳本內(nèi),有點(diǎn)類似于面向過程的編程理念。這樣的模式必定會(huì)導(dǎo)致編寫與維護(hù)的周期與成本增加,同樣也不利于團(tuán)隊(duì)內(nèi)成員共同維護(hù)的模式。
相較于傳統(tǒng)模式,PO(Page Object)模式則是將一個(gè)頁面的所有元素對象定位和對元素對象的操作封裝成類,測試用例的編寫也依照單個(gè)頁面來進(jìn)行,目的就是實(shí)現(xiàn)頁面對象和測試用例的分離。
這樣做的好處有3點(diǎn):
1 . 低耦合:將每個(gè)頁面單獨(dú)進(jìn)行封裝,類似與面向?qū)ο?#xff0c;互相之間低耦合,即時(shí)需要業(yè)務(wù)流程連續(xù)執(zhí)行也不會(huì)互相影響;
2 . 易維護(hù):當(dāng)界面發(fā)生變化時(shí),只需修改對應(yīng)的頁面類中的元素即可,其他相關(guān)的不會(huì)受到影響也無需修改;
3 . 易上手:基于PO模式的設(shè)計(jì)理念,頁面類的實(shí)現(xiàn)與細(xì)節(jié)不會(huì)暴露在外,都通過公共方法進(jìn)行提供,使用者無需對代碼的實(shí)現(xiàn)邏輯進(jìn)行學(xué)習(xí),只需要對業(yè)務(wù)與編程語言有足夠的了解后直接編寫與使用。
接下來了解了PO模式的優(yōu)勢之后,就需要對自動(dòng)化框架進(jìn)行設(shè)。先考慮清楚使用了自動(dòng)化測試框架是要解決什么問題,這里的問題不能是模糊且沒有邊界的,之后將要自動(dòng)化的產(chǎn)品、模塊、流程進(jìn)行分類與整理,這里一般來說推薦產(chǎn)品的核心主流程,一般覆蓋happy path即可,但如果需要加入一些反向用例與使用場景也是可以的,但切忌不要一股腦的把團(tuán)隊(duì)的手工測試用例都加進(jìn)去,到了后期你會(huì)體驗(yàn)到什么叫維護(hù)的時(shí)間比測試的時(shí)間更長。
決定好以上這些了之后,就可以進(jìn)行技術(shù)棧與框架的選擇了,那這里我們選用的是appium+python+unittest的組合來進(jìn)行PO模式測試框架的設(shè)計(jì)。當(dāng)然,這里還是推薦大家根據(jù)自己的技術(shù)棧與公司環(huán)境現(xiàn)狀來進(jìn)行有效選擇。
?現(xiàn)在我也找了很多測試的朋友,做了一個(gè)分享技術(shù)的交流群,共享了很多我們收集的技術(shù)文檔和視頻教程。
如果你不想再體驗(yàn)自學(xué)時(shí)找不到資源,沒人解答問題,堅(jiān)持幾天便放棄的感受
可以加入我們一起交流。而且還有很多在自動(dòng)化,性能,安全,測試開發(fā)等等方面有一定建樹的技術(shù)大牛
分享他們的經(jīng)驗(yàn),還會(huì)分享很多直播講座和技術(shù)沙龍
可以免費(fèi)學(xué)習(xí)!劃重點(diǎn)!開源的!!!
qq群號(hào):485187702【暗號(hào):csdn11】
4. PO模式
這里先聲明一點(diǎn),所有的框架都不是一蹴而就的,和我們熟知的軟件一樣,無論是結(jié)構(gòu)還是代碼都是的一版一版優(yōu)化出來的,所以大家現(xiàn)在看到的框架不會(huì)是最初與最終的模樣,無論是拿來優(yōu)化、二開還是直接使用都是可以的。如果是自己寫,哪怕一開始寫的很簡單也無所謂,要始終記住你落地自動(dòng)化的目的是什么,只要能針對產(chǎn)品持續(xù)優(yōu)化與反復(fù)總結(jié),相信會(huì)有令人滿意的結(jié)果的。
這里我們先將一個(gè)頁面類分成兩層,一個(gè)是對象操作層、另一個(gè)是業(yè)務(wù)層。對象操作層指的是頁面中的元素定位與單個(gè)元素操作;業(yè)務(wù)層顧名思義是把對應(yīng)的元素操作組合起來形成一些列的業(yè)務(wù)操作。
基于PO模式設(shè)計(jì)框架之前,我們還需要了解一下PO模式的6大原則,了解了原則之后才能更好的在實(shí)現(xiàn)過程中將PO模式的優(yōu)勢融入自己的框架之中。
6大原則
1.The public methods represent the services that the page offers
2.Try not to expose the internals of the page
3.Generally don’t make assertions
4.Methods return other PageObjects
5.Need not represent an entire page
6.Different results for the same action are modelled as different methods
1.用公共方法代表頁面提供的功能
2.不要暴露頁面元素到外部
3.一般不在方法內(nèi)加斷言
4.方法應(yīng)該返回其他PO對象
5.不需要封裝頁面內(nèi)所有元素
6.同樣的行為不同的結(jié)果可以封裝成不同的方法
個(gè)人解讀
1.一些可復(fù)用的操作,可以用公共的方法進(jìn)行統(tǒng)一封裝,即使不在同一頁面;
2.封裝實(shí)現(xiàn)方法,對外只提供方法名或接口名;
3.封裝的實(shí)現(xiàn)方法中不要使用斷言,把斷言可以統(tǒng)一放在測試用例中;
4.可以使用其他對象作為一個(gè)方法的返回結(jié)果,比如頁面的跳轉(zhuǎn),就可以用方法的結(jié)果進(jìn)行返回;
5.頁面中只對重要的元素進(jìn)行PO設(shè)計(jì),不重要的、非主流程的可以舍棄(這里可以更好的迎合只覆蓋happy path);
6.如果一個(gè)操作可能有多種結(jié)果的時(shí)候,將結(jié)果封裝成不同的方法,比如保存成功與保存失敗。
5. 框架設(shè)計(jì)
5.1 目錄結(jié)構(gòu)
這里簡單說明下目錄的結(jié)構(gòu):
base:存放一些框架與頁面的公共方法
po:存放所有的頁面,這里就是被測對象相關(guān)的被測頁面,不需要放全部頁面
result:存放相關(guān)的自動(dòng)化測試結(jié)果報(bào)告
test_case:存放測試用例
根目錄下還有一個(gè)run文件,這個(gè)是運(yùn)行主入口,可以設(shè)置運(yùn)行哪些測試用例集與使用什么樣的測試報(bào)告套件。
5.2 實(shí)現(xiàn)步驟
這里的PO模式設(shè)計(jì)其實(shí)沒有那么的復(fù)雜,從目錄就可以看出,首先將一些基礎(chǔ)的元素定位、通用操作封裝到對應(yīng)的BasePage類中,(這里插一句,其實(shí)做APP自動(dòng)化也好,做web自動(dòng)化也好,很大程度上開發(fā)的代碼規(guī)范性決定了你的框架實(shí)現(xiàn)過程是否順暢。所以這里大家也可以在平時(shí)的工作中與開發(fā)事先溝通好一些元素的屬性寫法規(guī)范,別覺得不可能,行不行事在人為。)
然后根據(jù)事先整理好的業(yè)務(wù)操作流程與頁面跳轉(zhuǎn)關(guān)系(3.設(shè)計(jì)理念中提到的前置工作輸出)進(jìn)行功能的封裝,這里推薦根據(jù)6大原則對相關(guān)操作進(jìn)行實(shí)現(xiàn),順了之后就是熟練工了,大同小異的。如果日后出現(xiàn)了布局變更或者業(yè)務(wù)變更,統(tǒng)一在對應(yīng)的po頁面中進(jìn)行修改即可。另外,一些業(yè)務(wù)邏輯的判斷,(比如是否存在該用戶,不存在新建,存在直接進(jìn)入),也可以放在po中,但是需要謹(jǐn)慎,這里比較推薦的還是放在測試用例內(nèi),也方便大家根據(jù)不同的情況做斷言。
最后在頁面元素、業(yè)務(wù)操作齊全的狀態(tài)下進(jìn)行測試用例的實(shí)現(xiàn),一般來說可以先使用冒煙測試的測試用例來進(jìn)行簡單的業(yè)務(wù)驗(yàn)證,當(dāng)然直接使用系統(tǒng)測試的測試用例也是完全沒問題的,之后只需要根據(jù)之前整理好的用例選單進(jìn)行轉(zhuǎn)化即可。至于用例的存放目錄結(jié)構(gòu)可以根據(jù)po頁面維度來存放,也可以根據(jù)業(yè)務(wù)維度來進(jìn)行存放,見仁見智。
5.3 具體實(shí)現(xiàn)
5.3.1 base部分
這邊先定義一個(gè)BasePage類,用來實(shí)現(xiàn)一些公共方法與元素定位的實(shí)現(xiàn)(webdriver)
class BasePage:
def __init__(self, driver):
self.driver = driver
self.driver.implicitly_wait(10)
def by_id(self, id):
return self.driver.find_element(By.ID, id)
def by_xpath(self, xpath):
return self.driver.find_element(By.XPATH, xpath)
def by_class_name(self, class_name):
return self.driver.find_element(By.CLASS_NAME, class_name)
def by_uiautomator(self, uiautomator):
return self.driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, uiautomator)
另外后續(xù)的一些觸屏的操作、元素判斷也可以按需放在這里面???????
def is_element(self, element):
source = self.driver.page_source
if element in source:
return True
else:
return False
def drag(self, bx=0.50, bw=0.05, by=0.4, bz=0.9):
x = self.driver.get_window_size()['width']
y = self.driver.get_window_size()['height']
sx = x * bx
ex = x * bw
sy = y * by
ey = y * bz
????????return?self.driver.swipe(sx,?sy,?ex,?ey,?1000)
這里我定義了另一個(gè)driver_setup的方法,方便每次設(shè)備啟動(dòng)使用
def driver_setup():
desired_caps = dict()
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '10'
desired_caps['deviceName'] = '你自己的設(shè)備名'
desired_caps['appPackage'] = '包名'
desired_caps['appActivity'] = '啟動(dòng)名'
desired_caps['noReset'] = True # 不重置session信息
desired_caps['fullReset'] = False # 效果類似與卸載APP 如果不想每次重新登錄,設(shè)為False
????return?desired_caps
5.3.2 po部分
?
目錄大致如上,這里值得注意的是,不要把APP里所有的頁面都加入到自動(dòng)化測試中,100%的自動(dòng)化測試覆蓋率會(huì)讓你苦不堪言,也大可不必。將每次必須回歸的重要流程與高重復(fù)業(yè)務(wù)流程、場景加入即可。
以下就是po中的創(chuàng)建顧客頁面的實(shí)現(xiàn)方法了,直接繼承BasePage類,這里有幾個(gè)例子需要關(guān)注的是,性別選擇可以封裝成兩個(gè)方法,盡量不用同一個(gè);另一個(gè)如果是點(diǎn)擊類事件(單結(jié)果事件),直接click就行,不用單獨(dú)在封裝完元素后再進(jìn)行業(yè)務(wù)操作封裝,備注這樣的多結(jié)果事件則要在下面單獨(dú)進(jìn)行業(yè)務(wù)指定。
class CustomerCreatePage(BasePage):
"""
定義封裝創(chuàng)建客戶頁面的各類操作
創(chuàng)建客
創(chuàng)建客戶并開卡
"""
# 定義會(huì)員編號(hào)輸入框
def customer_number(self):
return self.by_id('com.tiffany.rta.debug:id/edt_customer_number')
# 定義姓名輸入框
def customer_name(self):
return self.by_id('com.tiffany.rta.debug:id/edt_customer_name')
# 定義手機(jī)輸入框
def customer_mobile(self):
return self.by_id('com.tiffany.rta.debug:id/edt_customer_mobile')
# 定義性別選擇
def customer_sex(self):
return self.by_id('com.tiffany.rta.debug:id/tv_customer_sex')
# 定義性別內(nèi)選擇項(xiàng)目-男
def customer_sex_item_male(self):
return self.by_id('com.tiffany.rta.debug:id/tv_customer_boy').click()
# 定義性別內(nèi)選擇項(xiàng)目-女
def customer_sex_item_female(self):
return self.by_id('com.tiffany.rta.debug:id/tv_customer_girl').click()
# 定義生日選擇框
def customer_birthday(self):
return self.by_id('com.tiffany.rta.debug:id/tv_customer_birthday')
# 定義備注輸入框
def customer_memo(self):
return self.by_id('com.tiffany.rta.debug:id/ed_remark')
# 定義保存并開卡按鈕
def save_and_register_card_button(self):
????????return?self.by_id('com.tiffany.rta.debug:id/mb_save_open_card').click()
接下來就是組合多個(gè)元素進(jìn)行業(yè)務(wù)操作的定義???????
# 定義新建顧客操作
def do_create_customer(self):
self.customer_number().send_keys('00001')
self.customer_name().send_keys('自動(dòng)化測試01')
self.customer_mobile().send_keys('13200000000')
self.customer_sex()
self.customer_sex_item_male()
????????self.save_button()
5.3.3 test_case部分
測試用例類繼承unittest下的TestCase,初始化的時(shí)候?qū)?yīng)的用例業(yè)務(wù)流程加入到里面,另外在具體的測試用例中需要加對應(yīng)的判斷邏輯與操作步驟完整的添加在里面。使用try捕獲異常的時(shí)候記得把對應(yīng)的報(bào)錯(cuò)名也寫上,一是方便定位問題,二是有可能會(huì)導(dǎo)致即使用例失敗,測試報(bào)告上的結(jié)果也是pass。
class TestCustomerListPage(unittest.TestCase):
"""
定義客戶列表界面的測試用例
創(chuàng)建客戶
"""
# 初始化必要的設(shè)備信息與業(yè)務(wù)頁面
def setUp(self):
self.driver = webdriver.Remote('http://localhost:4723/wd/hub', driver_setup())
self.base_page = BasePage(driver=self.driver)
self.home_page = HomePage(driver=self.driver)
self.customer_list = CustomerListPage(driver=self.driver)
self.customer_detail = CustomerDetailPage(driver=self.driver)
self.customer_create = CustomerCreatePage(driver=self.driver)
# 測試用例1 -- 創(chuàng)建顧客
def test_1_create_customer(self):
self.home_page.go_customer()
customer_name = '自動(dòng)化測試01'
# 業(yè)務(wù)邏輯判斷 -- 是否存在該新客
if self.base_page.is_element(customer_name):
self.customer_list.select_customer()
self.customer_detail.do_delete_customer()
self.home_page.go_index()
self.home_page.go_customer()
if self.base_page.is_element(customer_name):
self.customer_check.check_pass()
else:
self.customer_list.goto_create_customer()
self.customer_create.do_create_customer()
self.customer_detail.back_button()
else:
self.customer_list.goto_create_customer()
self.customer_create.do_create_customer()
self.customer_detail.back_button()
try:
self.assertTrue(self.driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR,
'new UiSelector().text("自動(dòng)化測試01")'))
except NoSuchElementException as e:
return e
sleep(5)
def tearDown(self):
self.driver.quit()
if __name__ == "__main__":
unittest.main()
5.3.4 run部分
具體的測試用例報(bào)告模板,大家可以自由選擇,這邊使用的是 HTMLTestReportCN,啟動(dòng)的方式都是大同小異的,無非就是根據(jù)自己的測試場景進(jìn)行定制就行。另外測試模板的組合和樣式有興趣的同學(xué)可以自己對報(bào)告腳本進(jìn)行修改,打造更適合自己團(tuán)隊(duì)需求的測試報(bào)告。???????
# 兩套測試報(bào)告模板路徑,只用一個(gè)的可以就定義一個(gè)
report_path = os.path.join(os.getcwd() + '\\result')
result_path = os.path.join(report_path, 'report.html')
# 測試套件路徑,根據(jù)需求修改
test_dir = os.path.join(os.getcwd() + '\\test_case\\trade')
# 執(zhí)行指定測試用例
def test_suit():
suit = unittest.TestSuite()
suit.addTest(TestOrderResultPage('test_1_order_result'))
suit.addTest(TestOrderResultPage('test_2_order_result_home_page'))
return suit
# 執(zhí)行測試用例集
dis = unittest.defaultTestLoader.discover(test_dir, pattern="test*.py")
if __name__ == "__main__":
with open(result_path, 'wb') as fp:
runner = HTMLTestReportCN.HTMLTestRunner(stream=fp, title='自動(dòng)化APP測試報(bào)告',
description='基于自動(dòng)化APP測試框架產(chǎn)生的測試報(bào)告')
runner.run(test_suit())
6. 注意點(diǎn)
1.PO模式雖然可以解決UI自動(dòng)化測試中設(shè)計(jì)的部分問題,也仍然是目前比較主流的設(shè)計(jì)方案,后期面對大量的業(yè)務(wù)頁面增加的情況,雖然可以使用通用頁面來解決部分問題,但仍然避免不了界面與業(yè)務(wù)改動(dòng)后大量調(diào)試代碼的情況出現(xiàn)。
所以這也是很多公司無法將大量成本聚焦在UI自動(dòng)化測試的原因,將UI自動(dòng)化應(yīng)用于部分主要業(yè)務(wù)的做法還是值得提倡的,它也只是提高測試團(tuán)隊(duì)工作效率與投入產(chǎn)出比的一項(xiàng)手段而已,千萬不可本末倒置;
2.測試用例的合理設(shè)計(jì)與執(zhí)行安排,如果你的測試用例的相關(guān)命名、流程設(shè)計(jì)、存放路徑過于凌亂與潦草的話,相信我,后期當(dāng)框架具有一定的規(guī)模后,你會(huì)發(fā)現(xiàn)往往在維護(hù)測試用例時(shí)花費(fèi)的精力要遠(yuǎn)遠(yuǎn)大于你的執(zhí)行時(shí)間。
與手工測試用例一樣,無效用例始終都會(huì)出現(xiàn)在你的框架之中,這是無可避免的,但如何快速定位與規(guī)整這些用例就成了后期需要面對的日常問題之一,所以用例實(shí)現(xiàn)之初的命名規(guī)則、存放路徑、實(shí)現(xiàn)時(shí)的備注就成了日后減少維護(hù)工作量的良好開端;
3.相較于接口自動(dòng)化,UI自動(dòng)化的性價(jià)比還是有一定的局限性,針對這樣的情況,測試團(tuán)隊(duì)中如果要投入U(xiǎn)I自動(dòng)化的話可能就需要將團(tuán)隊(duì)中的成員定位做好一定的有效安排。
框架設(shè)計(jì)與實(shí)現(xiàn)的問題不大,有專業(yè)的業(yè)務(wù)理解與一定的代碼功底一般都可以很好的完成對應(yīng)的測試框架,這里只針對維護(hù)層面的工作來說,是專職人員定崗安排還是團(tuán)隊(duì)成員穿插進(jìn)行都需要根據(jù)各自的團(tuán)隊(duì)實(shí)際情況來分配,各有利弊,畢竟維護(hù)是一件費(fèi)時(shí)費(fèi)力的持久性工作。