簡(jiǎn)介
?獲取AppPackage和AppActivity
?定位UI控件的工具
?腳本結(jié)構(gòu)
?PageObject分層管理
?HTMLTestRunner生成測(cè)試報(bào)告
?啟動(dòng)appium server服務(wù)
?以python文件模式執(zhí)行腳本生成測(cè)試報(bào)告
下載與安裝
下載需要自動(dòng)化測(cè)試的App并安裝到手機(jī)
獲取AppPackage和AppActivity
方法一
有源碼的情況直接打開AndroidManifest.xml文件,文件會(huì)有package信息
android.intent.action.MAIN決定應(yīng)用程序最先啟動(dòng)的Activity
android.intent.category.LAUNCHER決定應(yīng)用程序是否顯示在程序列表里
方法二
反編譯apk,反編譯后打開AndroidManifest.xml文件,文件會(huì)有package信息
方法三
aapt dump badging F:\****.apk
aapt工具是sdk自帶的一個(gè)工具,在sdk\builds-tools\目錄下,將appt.exe所在路徑添加至path環(huán)境變量里,cmd輸入aapt查看是否可使用,有如下響應(yīng)內(nèi)容即成功
將需要查看的apk復(fù)制到電腦任意路徑下,例如F:\1.apk
使用命令 aapt dump badging F:\1.apk
運(yùn)行后的結(jié)果前兩行分別是包名appPackage和Activity
aapt dump xmltree F:\****.apk AndroidManifest.xml
方法四
將需要查看的apk復(fù)制到電腦任意路徑下,例如F:\1.apk
使用命令 aapt dump xmltree F:\1.apk AndroidManifest.xml
運(yùn)行后的結(jié)果就有包名appPackage和Activity
??方法五
adb logcat -c //清除logcat內(nèi)容 adb logcat ActivityManager:I *:s //僅輸出標(biāo)記為“ActivityManager”并且優(yōu)先級(jí)大于等于“Info”的日志,*:S用于設(shè)置所有標(biāo)記的日志優(yōu)先級(jí)為S(無記載,最高優(yōu)先級(jí),沒有什么會(huì)被記載)
手機(jī)啟動(dòng)要查看的app,就會(huì)加載日志信息
結(jié)果如下圖:
??方法六
adb logcat > D:/logs.txt 或 adb logcat|find "Displayed" >d:/logs.txt
啟動(dòng)app,cmd輸入adb?logcat > D:/logs.txt(開啟日志),輸入Ctrl+C(關(guān)閉日志),在日志查找appPackage和AppActivity,文件內(nèi)搜索Displayed找到Package和Activity信息
?或使用該命令直接過濾再保存到txt文件內(nèi) adb logcat|find "Displayed" >d:/logs.txt
最終,得到App的信息如下:
1 appPackage:com.nbi.aquatic
2 appActivity:.ui.login.LoginActivity
定位UI控件的工具
使用Android SDK的uiautomatorviewer.bat(在..\sdk\tools\ 目錄下),電腦開啟開發(fā)者模式,可以使用adb命令的狀態(tài)下使用該sdk自帶的工具,可視化安卓手機(jī)的界面信息
★ 腳本結(jié)構(gòu)
somke_test.py 存放測(cè)試集
config.py 存放自動(dòng)化測(cè)試所用到的數(shù)據(jù),如賬號(hào)密碼,默認(rèn)密碼等
pool.py等 測(cè)試集中的一個(gè)測(cè)試用例的page層
base.py 頁(yè)面基礎(chǔ)層,供page層繼承
HTMLTestRunner.py 生成測(cè)試報(bào)告的模塊,可集成到代碼里不需在環(huán)境中安裝該模塊,也可在電腦python環(huán)境里安裝配置
(自行百度:Pycharm使用python3無法通過HTMLTestRunner生成測(cè)試報(bào)告)
config.py 存放自動(dòng)化測(cè)試所用到的數(shù)據(jù),如賬號(hào)密碼,默認(rèn)密碼等
1 settings = {
2 'admin': {
3 'number': '13600000000',
4 'password': 'qaz123'
5 },
6 'default_password': 'a123456'
7 }
8 ADMIN_NUMBER = settings['admin']['number']
9 ADMIN_PASSWORD = settings['admin']['password']
啟動(dòng)app的相關(guān)配置傳到appium服務(wù)端和連接手機(jī)的代碼寫在測(cè)試集TestCase外面,如果寫在初始化測(cè)試平臺(tái)的測(cè)試用例里則只能啟動(dòng)執(zhí)行一次用例
1 desired_caps = {}
2 # Android自動(dòng)化還是Ios自動(dòng)化
3 desired_caps['platformName'] = 'Android'
4 # Android操作系統(tǒng)版本
5 desired_caps['platformVersion'] = '5.1'
6 # 設(shè)備名稱
7 desired_caps['deviceName'] = '127.0.0.1:62001'
8 # 被測(cè)App包名
9 desired_caps['appPackage'] = 'com.nbi.aquatic'
10 # 被測(cè)App的入口Activity名
11 desired_caps['appActivity'] = '.ui.login.LoginActivity'
12 desired_caps['automationName'] = 'Uiautomator2'
13 # 把以上配置傳到appium服務(wù)端并連接手機(jī)
14 driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
啟動(dòng)app,用到的是unittest自帶的setUp方法
1 def setUp(self):
2 # 初始化測(cè)試平臺(tái)
3 self.driver = driver
關(guān)閉app,用到的不是unittest自帶的tearDown方法,而是自定義了一個(gè)test_*_end_testing函數(shù),這個(gè)函數(shù)負(fù)責(zé)關(guān)閉app,是在測(cè)試集里的最后一個(gè)測(cè)試用例
1 def test_36_end_testing(self):
2 """結(jié)束測(cè)試"""
3 self.driver.quit()
整體測(cè)試用例結(jié)構(gòu),采用PageObject分層管理
1.一個(gè)測(cè)試用例就是一個(gè)函數(shù),后期增加用例時(shí)在后面增加新函數(shù)即可
2.為了使用unittest框架執(zhí)行測(cè)試集,命名都以test開頭,例如test_16_creat_aquatype
3.每個(gè)用例又分獨(dú)立的page層,例如測(cè)試集里的用例test_16_creat_aquatype,其page層就是PoolPage,在編寫測(cè)試集時(shí)引入該文件即可,也就是testcase層調(diào)用page層
1 from appium import webdriver
2 from test_case.page_object.admin.pool import PoolPage
3 import unittest
4 import config
5 import time
6 class SmokeTest(unittest.TestCase):
7 def setUp(self):
8 # 初始化測(cè)試平臺(tái)
9 self.driver = driver
10 def test_10_admin_login(self):
11 """手機(jī)登錄"""
12 LoginPage(self.driver).PhoneNumberlogin_action(
13 config.ADMIN_NUMBER,
14 config.ADMIN_PASSWORD,
15 )
16 def test_16_creat_aquatype(self):
17 """添加水產(chǎn)類型"""
18 PoolPage(self.driver).creat_aquatype(new_aquatype_name)
19 def test_17_creat_aquatic(self):
20 """養(yǎng)殖池添加養(yǎng)殖"""
21 PoolPage(self.driver).creat_aquatic()
22 def test_36_end_testing(self):
23 """結(jié)束測(cè)試"""
24 self.driver.quit()
25 if __name__ == '__main__':
26 # 定義一個(gè)單元測(cè)試容器
27 suite = unittest.TestSuite()
28 # addTest添加case到suite容器中,構(gòu)造測(cè)試集
29 suite.addTest(SmokeTest('test_10_admin_login'))
30 suite.addTest(SmokeTest('test_16_creat_aquatype'))
31 suite.addTest(SmokeTest('test_17_creat_aquatic'))
32 suite.addTest(SmokeTest('test_36_end_testing'))
33 # 執(zhí)行case
34 runner.run(suite)
4.測(cè)試用例test_16_creat_aquatype的page層就是PoolPage,每個(gè)page層又都繼承頁(yè)面基礎(chǔ)層BasePage
1 from selenium.webdriver.common.by import By
2 from test_case.page_object.base import BasePage
3 import time
4 class PoolPage(BasePage):
5 """定位元素"""
6 creataquatic_btn_loc = (By.ID, 'com.nbi.aquatic:id/tv_add_breed')
7 select_starttime_btn_loc = (By.ID, 'com.nbi.aquatic:id/textView158')
8 # 添加水產(chǎn)類型(水產(chǎn)名稱最長(zhǎng)10個(gè)字符)
9 def creat_aquatype(self, aquatype_name):
10 time.sleep(3)
11 self.find_element(*self.creataquatic_btn_loc).click()
12 .......
13 # 養(yǎng)殖池添加養(yǎng)殖
14 def creat_aquatic(self):
15 self.find_element(*self.select_starttime_btn_loc).click()
5.頁(yè)面基礎(chǔ)層BasePage
1 from selenium.webdriver.support.ui import WebDriverWait
2 from selenium.webdriver.support import expected_conditions as EC
3 class BasePage(object):
4 """頁(yè)面基礎(chǔ)類,用于所有頁(yè)面的繼承"""
5 def __init__(self, selenium_driver):
6 self.driver = selenium_driver
7 self.timeout = 30
8 self.poll_frequency = 0.1
9
10 def find_element(self, *loc):
11 return self.driver.find_element(*loc)
12
13 def find_elements(self, *loc):
14 return self.driver.find_elements(*loc)
15
16 def content_appeared(self):
17 self.find_element()
18
19 def wait(self, loc):
20 WebDriverWait(self.driver, 10, 0.005).until(
21 EC.visibility_of_element_located(loc)
22 )
23
24 def wait_and_compare(self, loc, text):
25 WebDriverWait(self.driver, 30, 0.5).until(
26 EC.text_to_be_present_in_element(loc, text)
27 )
生成HTML測(cè)試結(jié)果報(bào)告
引入方式一,直接電腦python環(huán)境安裝HTMLTestRunner模塊
1 import HTMLTestRunner
2 if __name__ == '__main__':
3 suite = unittest.TestSuite()
4 suite.addTest(SmokeTest('test_*_*'))
5 # 寫法一
6 timestr = time.strftime('%Y%m%d', time.localtime(time.time())) # 本地日期作為報(bào)告名字
7 filename = 'F:\\folder_data\\' # 文件名字及保存路徑
8 fp = open(filename + (timestr + '.html'), 'wb')
9 runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title='冒煙測(cè)試報(bào)告', description='用例執(zhí)行情況: ')
10
11 # 寫法二
12 timestr = time.strftime('%Y%m%d', time.localtime(time.time()))
13 filename = '../_reports/' + timestr + '.html'
14 fp = open(filename, 'wb')
15 runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title='冒煙測(cè)試報(bào)告', description='用例執(zhí)行情況: ')
16
17 # 執(zhí)行case,并生成一份測(cè)試報(bào)告
18 runner.run(suite)
19 fp.close()
引入方式二,將HTMLTestRunner下載集成在代碼內(nèi)文章來源:http://www.zghlxwxcb.cn/news/detail-502763.html
模塊下載地址:HTMLTestRunner - tungwaiyip's software文章來源地址http://www.zghlxwxcb.cn/news/detail-502763.html
1 from packages.HTMLTestRunner import HTMLTestRunner
2 if __name__ == '__main__':
3 suite = unittest.TestSuite()
4 suite.addTest(SmokeTest('test_*_*'))
5 # 寫法三
6 fp = open('../_reports/result.html', 'wb')
7 runner = HTMLTestRunner(stream=fp, title='冒煙測(cè)試報(bào)告', description='用例執(zhí)行情況: ')
8 # 執(zhí)行case,并生成一份測(cè)試報(bào)告
9 runner.run(suite)
10 fp.close()
到了這里,關(guān)于【編寫UI自動(dòng)化測(cè)試集】Appium+Python+Unittest+HTMLRunner?的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!