1. 程式人生 > >基於appium的app自動化測試框架

基於appium的app自動化測試框架

基於appium框架的app自動化測試
App自動化測試主要難點在於環境的搭建,appium完全是基於selenium進行的擴充套件,所以app測試框架也是基於web測試框架開發的
一、裝置連線
(即構建基礎的測試環境,保證可以驅動裝置進行操作)
0.準備測試環境
1)安裝jdk配置java_home環境變數;
2)安裝Android SDK(安卓軟體開發包)(adb、appt )
3)安裝nodejs,並通過npm安裝appium
1.獲取app包名appPackage
在cmd命令列中輸入aapt  dump badging +apk包目錄
如果提示aapt命令不是內部命令,說明aapt的環境變數配置有問題。
可以直接到android-sdk-windows的安裝目錄下找到aapt程式,在位址列中輸入cmd,然後在執行上面操作,就可以了。

如果執行指令碼出現“no such element: Unable to locate element: {"method":"css selector","selector":"#i1"}
(Session info: webview=39.0.0.0)”原因是不明未解決。一般是在模擬機上會出現這種定位問題,真機沒有。
成功的結果是這樣的,截圖如下:

2.獲取app入口appActivity的值
還是在上面的資訊中往下找找到如下圖的位置,其中name的值就是appActivity的引數值

 接下來我們可以啟動appium軟體,直接啟動服務appium-server。

 

然後,通過以上方法獲取關於app模組資訊,我們可以嘗試寫一下指令碼驅動appium-server來幫我連線到裝置上的app軟體。指令碼命令如下:
指令碼完成後,右鍵執行一下,會發現appium在不停的刷日誌(確保appium和指令碼在同一網段即可,不一定在同一臺電腦)

這樣就證明code-client和appium已經建立了聯絡,然後我們就可以通過寫指令碼命令操作裝置上的軟體了。
如果我們要操作手機上自帶的軟體/功能,沒有辦法獲取apk包怎麼辦呢?
答:進入cmd命令列中輸入adb logcat |findStr  START  ,然後操作裝置上的功能/軟體,在打出的日誌中查詢第一個START,在其後cmp=後面就是報名appPackage和appActivity

 

===============================================================================
二、搭建自動化測試框架
1、整體思路:建立基礎類實現裝置驅動的獲取連線
2、建立頁面類實現頁面中所有的功能元素可被獲取呼叫(程式碼驅動編寫測試用例)
3、建立測試指令碼(測試類),編寫測試方法呼叫測試用例
4、建立服務控制類,通過引數配置的方式連線不同的裝置
5、建立框架的啟動指令碼
具體程式碼如下:
1.建立基礎類實現裝置驅動的獲取連線
1)編寫基礎類,例項化封裝後的appium框架(即Pyapp)	
2.建立頁面類實現頁面中所有的功能元素可被獲取呼叫(程式碼驅動編寫測試用例)
2)編寫登入頁面類,實現登入頁面的功能操作
3)編寫單個頁面功能的測試方法
4)逐一編寫測試功能頁面類的相關功能



3.建立測試指令碼(測試類),編寫測試方法呼叫測試用例

 

4.建立服務控制類,通過引數配置的方式連線不同的裝置
1)新建yml檔案編寫測試裝置的詳細資訊

 

2)建立服務控制類:服務控制類:appium服務的停止、啟動、監聽;裝置驅動的連線啟動
class Controller(object):
    #讀取裝置配置檔案中的裝置資訊進行初始化
    def __init__(self):
        # 通過讀取yml檔案獲取 配置資訊
        self.conf = Tool().app_data
        # 拆分包的資訊
        self.tester = self.conf.get('tester')
        # 拆分手機的資訊
        self.devices = self.conf.get('devices')
        # 手機的型別
        self.device_type = self.conf.get('device_type')
        # 唯一手機
        self.device = self.devices.get(self.device_type)[0]
        # 手機名稱
        self.deviceName = self.device.get('name')
    #啟動appium服務,由於我們是程式碼驅動,就不能使用手工開啟appium
    def start_server(self):
        device = self.devices.get(self.device_type)[0]
        ip = device.get('ip')
        port = device.get('port')
        deviceName = device.get('deviceName')
        log = os.path.join(LOGPATH, device.get('name') + '.log')
        cmd = 'appium -a {ip} -p {port} -U {deviceName} -g {log}'.format(
            ip=ip, port=port, deviceName=deviceName, log=log)
        logger.debug('啟動服務的命令:%s'%cmd)
        # 執行命令 netstat -ano | findstr  9036 --  netstat -nlpt |grep 9036
        subprocess.Popen(cmd, stdout=open(log, 'a+'), stderr=subprocess.PIPE, shell=True)
    #監聽appium服務是否啟動成功
    def test_server(self):
        port = self.devices.get(self.device_type)[0].get('port')
        while True:
            #在cmd命令列中執行netstat -ano |findstr 埠,監聽服務是否啟動成功
            res = subprocess.getoutput("netstat -ano | findstr %s" % port)
            if 'LISTENING' in res:
                logger.debug(res)
                logger.info("服務啟動成功")
                break
            else:
                time.sleep(3)
                logger.debug('三秒後重試')
        return True
    #開啟手機啟動的連線
    def start_driver(self):
        # 包資訊 和 手機資訊 合併
        self.tester.update(self.device)
        ip = self.tester.get('ip')
        port = self.tester.get('port')
        driver = webdriver.Remote('http://{ip}:{port}/wd/hub'.format(ip=ip,port=port),self.tester)
        # 像對列中put生成的drvier
        driver_queue.put(driver)
    #關閉appium服務
    def kill_server(self):
        res = subprocess.getoutput("taskkill /F /IM node.exe /t")
        logger.debug('kill server :%s'%res)
if __name__ == '__main__':
    contorller = Controller()
    contorller.kill_server()
    contorller.start_server()
    if contorller.test_server():
        contorller.start_driver()

5.建立框架的啟動指令碼
主要負責啟動appium服務、啟動裝置驅動連線裝置、執行測試用例、生成測試報告。

詳細程式碼:
class Main(object):
    def __init__(self):
        self.controller = Controller()
        self.deviceName = self.controller.deviceName

    def run(self):
        self.controller.start_server()
        if self.controller.test_server():
            self.controller.start_driver()
            suite = unittest.TestSuite()
            cases = unittest.defaultTestLoader.discover(APPCASE)
            for case in cases:
                suite.addTest(case)
            f = open(APPREPORT.format('{}.html'.format(self.deviceName)), 'wb')
            runner = HTMLTestRunner(f, verbosity=1, title=u'測試報告', description=u'用例執行情況:')
            runner.run(suite)
            f.flush()
            f.close()


if __name__ == '__main__':
    m = Main()
    m.run()

==============================================================================

三、編寫測試用例過程中常見的問題:
1.如果執行以上指令碼後,提示“無法與計算機取得聯絡”

一般原因有兩個(1.appium未開啟,2.appium服務和指令碼服務不在一個網段內。)
2. 有時候聯絡兩次執行指令碼會出現“A new session could not be created. Details”

原因是:appium-server和code-client已經連線,無法再去連線。這裡我們可以將appium-server服務關閉然後在新建一個appium-server。在執行指令碼就好了。


主要原因是selenium的版本問題,可是使用set_value()代替send_keys()方法。