色综合图-色综合图片-色综合图片二区150p-色综合图区-玖玖国产精品视频-玖玖香蕉视频

您的位置:首頁技術(shù)文章
文章詳情頁

python+appium+yaml移動(dòng)端自動(dòng)化測試框架實(shí)現(xiàn)詳解

瀏覽:62日期:2022-07-04 14:58:24

結(jié)構(gòu)介紹

之前分享過一篇安卓UI測試,但是沒有實(shí)現(xiàn)數(shù)據(jù)與代碼分離,后期維護(hù)成本較高,所以最近抽空優(yōu)化了一下。不想看文章得可以直接去Github,歡迎拍磚大致結(jié)構(gòu)如下:

python+appium+yaml移動(dòng)端自動(dòng)化測試框架實(shí)現(xiàn)詳解

testyaml管理用例,實(shí)現(xiàn)數(shù)據(jù)與代碼分離,一個(gè)模塊一個(gè)文件夾

public 存放公共文件,如讀取配置文件、啟動(dòng)appium服務(wù)、讀取Yaml文件、定義日志格式等

page 存放最小測試用例集,一個(gè)模塊一個(gè)文件夾

results 存放測試報(bào)告及失敗截圖

python+appium+yaml移動(dòng)端自動(dòng)化測試框架實(shí)現(xiàn)詳解

logs 存放日志

python+appium+yaml移動(dòng)端自動(dòng)化測試框架實(shí)現(xiàn)詳解

python+appium+yaml移動(dòng)端自動(dòng)化測試框架實(shí)現(xiàn)詳解

testcase 存放測試用例runtest.py 運(yùn)行所有測試用例

yaml格式介紹

首先看下yaml文件的格式,之前也寫過一點(diǎn)關(guān)于yaml語法學(xué)習(xí)的文章testcase部分是重點(diǎn),其中:

element_info:定位元素信息

find_type:屬性,id、xpath、text、ids

operate_type: click、sendkeys、back、swipe_up 為back就是返回,暫時(shí)就四種

上面三個(gè)必填,operate_type必填!!!!!!

send_content:send_keys 時(shí)用到

index:ids時(shí)用到

times: 返回次數(shù)或者上滑次數(shù)

testinfo: - id: cm001 title: 新增終端門店 execute: 1testcase: - element_info: 客戶 find_type: text operate_type: click - element_info: com.fiberhome.waiqin365.client:id/cm_topbar_tv_right find_type: id operate_type: click - element_info: com.fiberhome.waiqin365.client:id/custview_id_singletv_inputtext find_type: ids operate_type: send_keys send_content: auto0205 index: 0 - element_info: find_type: operate_type: swipe_up times: 1 - element_info: 提交 find_type: text operate_type: click - element_info: find_type: operate_type: back times: 1

代碼部分

公共部分

個(gè)人覺得核心的就是公共部分,相當(dāng)于建房子,公共部分搞好了,后面僅僅是調(diào)用即可,建房子把架子搭好,后面就添磚加瓦吧。

讀取配置文件readconfig.py設(shè)置日志格式logs.py獲取設(shè)備GetDevices.py這幾個(gè)通用的就不做介紹了

讀取yaml文件 GetYaml.py主要用來讀取yaml文件

#coding=utf-8#author=’Shichao-Dong’ import sysreload(sys)sys.setdefaultencoding(’utf8’)import yamlimport codecs class getyaml: def __init__(self,path): self.path = path def getYaml(self): ’’’ 讀取yaml文件 :param path: 文件路徑 :return: ’’’ try: f = open(self.path) data =yaml.load(f) f.close() return data except Exception: print(u'未找到y(tǒng)aml文件') def alldata(self): data =self.getYaml() return data def caselen(self): data = self.alldata() length = len(data[’testcase’]) return length def get_elementinfo(self,i): data = self.alldata() # print data[’testcase’][i][’element_info’] return data[’testcase’][i][’element_info’] def get_findtype(self,i): data = self.alldata() # print data[’testcase’][i][’find_type’] return data[’testcase’][i][’find_type’] def get_operate_type(self,i): data = self.alldata() # print data[’testcase’][i][’operate_type’] return data[’testcase’][i][’operate_type’] def get_index(self,i): data = self.alldata() if self.get_findtype(i)==’ids’: return data[’testcase’][i][’index’] else: pass def get_send_content(self,i): data = self.alldata() # print data[’testcase’][i][’send_content’] if self.get_operate_type(i) == ’send_keys’: return data[’testcase’][i][’send_content’] else: pass def get_backtimes(self,i): data = self.alldata() if self.get_operate_type(i)==’back’ or self.get_operate_type(i)==’swipe_up’: return data[’testcase’][i][’times’] else: pass def get_title(self): data = self.alldata() # print data[’testinfo’][0][’title’] return data[’testinfo’][0][’title’]

啟動(dòng)appium服務(wù) StartAppiumServer.py主要是啟動(dòng)appium并返回端口port,這個(gè)port在下面的driver中需要

#coding=utf-8#author=’Shichao-Dong’ from logs import logimport random,timeimport platformimport osfrom GetDevices import devices log = log()dev = devices().get_deviceName() class Sp: def __init__(self, device): self.device = device def __start_driver(self, aport, bpport): ''' :return: ''' if platform.system() == ’Windows’: import subprocess subprocess.Popen('appium -p %s -bp %s -U %s' %(aport, bpport, self.device), shell=True) def start_appium(self): ''' 啟動(dòng)appium p:appium port bp:bootstrap port :return: 返回appium端口參數(shù) ''' aport = random.randint(4700, 4900) bpport = random.randint(4700, 4900) self.__start_driver(aport, bpport) log.info( ’start appium :p %s bp %s device:%s’ % (aport, bpport, self.device)) time.sleep(10) return aport def main(self): ''' :return: 啟動(dòng)appium ''' return self.start_appium() def stop_appium(self): ’’’ 停止appium :return: ’’’ if platform.system() == ’Windows’: os.popen('taskkill /f /im node.exe') if __name__ == ’__main__’: s = Sp(dev) s.main()

獲取driver GetDriver.pyplatformName、deviceName、appPackage、appActivity這些卸載配置文件config.ini文件中,可以直接通過readconfig.py文件讀取獲得。appium_port有StartAppiumServer.py文件返回

s = Sp(deviceName)appium_port = s.main() def mydriver(): desired_caps = { ’platformName’:platformName,’deviceName’:deviceName, ’platformVersion’:platformVersion, ’appPackage’:appPackage,’appActivity’:appActivity, ’unicodeKeyboard’:True,’resetKeyboard’:True,’noReset’:True } try: driver = webdriver.Remote(’http://127.0.0.1:%s/wd/hub’%appium_port,desired_caps) time.sleep(4) log.info(’獲取driver成功’) return driver except WebDriverException: print ’No driver’ if __name__ == '__main__': mydriver()

重新封裝find等命令,BaseOperate.py里面主要是一些上滑、返回、find等一些基礎(chǔ)操作

#coding=utf-8#author=’Shichao-Dong’ from selenium.webdriver.support.ui import WebDriverWaitfrom logs import logimport osimport time ’’’一些基礎(chǔ)操作:滑動(dòng)、截圖、點(diǎn)擊頁面元素等’’’ class BaseOperate: def __init__(self,driver): self.driver = driver def back(self): ’’’ 返回鍵 :return: ’’’ os.popen('adb shell input keyevent 4') def get_window_size(self): ’’’ 獲取屏幕大小 :return: windowsize ’’’ global windowSize windowSize = self.driver.get_window_size() return windowSize def swipe_up(self): ’’’ 向上滑動(dòng) :return: ’’’ windowsSize = self.get_window_size() width = windowsSize.get('width') height = windowsSize.get('height') self.driver.swipe(width/2, height*3/4, width/2, height/4, 1000) def screenshot(self): now=time.strftime('%y%m%d-%H-%M-%S') PATH = lambda p: os.path.abspath( os.path.join(os.path.dirname(__file__), p) ) screenshoot_path = PATH(’../results/screenshoot/’) self.driver.get_screenshot_as_file(screenshoot_path+now+’.png’) def find_id(self,id): ’’’ 尋找元素 :return: ’’’ exsit = self.driver.find_element_by_id(id) if exsit : return True else: return False def find_name(self,name): ’’’ 判斷頁面是否存在某個(gè)元素 :param name: text :return: ’’’ findname = '//*[@text=’%s’]'%(name) exsit = self.driver.find_element_by_xpath(findname) if exsit : return True else: return False def get_name(self,name): ’’’ 定位頁面text元素 :param name: :return: ’’’ # element = driver.find_element_by_name(name) # return element findname = '//*[@text=’%s’]'%(name) try: element = WebDriverWait(self.driver, 10).until(lambda x: x.find_element_by_xpath(findname)) # element = self.driver.find_element_by_xpath(findname) self.driver.implicitly_wait(2) return element except: self.screenshot() log.error(’未定位到元素:’+’%s’)%(name) def get_id(self,id): ’’’ 定位頁面resouce-id元素 :param id: :return: ’’’ try: element = WebDriverWait(self.driver, 10).until(lambda x: x.find_element_by_id(id)) # element = self.driver.find_element_by_id(id) self.driver.implicitly_wait(2) return element except: self.screenshot() log.error(’未定位到元素:’+’%s’)%(id) def get_xpath(self,xpath): ’’’ 定位頁面xpath元素 :param id: :return: ’’’ try: element = WebDriverWait(self.driver, 10).until(lambda x: x.find_element_by_xpath(xpath)) # element = self.driver.find_element_by_xpath(xpath) self.driver.implicitly_wait(2) return element except: self.screenshot() log.error(’未定位到元素:’+’%s’)%(xpath) def get_ids(self,id): ’’’ 定位頁面resouce-id元素組 :param id: :return:列表 ’’’ try: # elements = self.driver.find_elements_by_id(id) elements = WebDriverWait(self.driver, 10).until(lambda x: x.find_elements_by_id(id)) self.driver.implicitly_wait(2) return elements except: self.screenshot() log.error(’未定位到元素:’+’%s’)%(id) def page(self,name): ’’’ 返回至指定頁面 :return: ’’’ i=0 while i<10: i=i+1 try: findname = '//*[@text=’%s’]'%(name) self.driver.find_element_by_xpath(findname) self.driver.implicitly_wait(2) break except : os.popen('adb shell input keyevent 4') try: findname = '//*[@text=’確定’]' self.driver.find_element_by_xpath(findname).click() self.driver.implicitly_wait(2) except: os.popen('adb shell input keyevent 4') try: self.driver.find_element_by_xpath('//*[@text=’工作臺(tái)’]') self.driver.implicitly_wait(2) break except: os.popen('adb shell input keyevent 4')

Operate.py我認(rèn)為最關(guān)鍵的一步了,后面沒有page都是調(diào)用這個(gè)文件進(jìn)行測試,主要是根據(jù)讀取的yaml文件,然后進(jìn)行if...else...判斷,根據(jù)對(duì)應(yīng)的operate_type分別進(jìn)行對(duì)應(yīng)的click、sendkeys等操作

#coding=utf-8#author=’Shichao-Dong’ from GetYaml import getyamlfrom BaseOperate import BaseOperate class Operate: def __init__(self,path,driver): self.path = path self.driver = driver self.yaml = getyaml(self.path) self.baseoperate=BaseOperate(driver) def check_operate_type(self): ’’’ 讀取yaml信息并執(zhí)行 element_info:定位元素信息 find_type:屬性,id、xpath、text、ids operate_type: click、sendkeys、back、swipe_up 為back就是返回,暫時(shí)就三種 上面三個(gè)必填,operate_type必填!!!!!! send_content:send_keys 時(shí)用到 index:ids時(shí)用到 times: :return: ’’’ for i in range(self.yaml.caselen()): if self.yaml.get_operate_type(i) == ’click’: if self.yaml.get_findtype(i) == ’text’: self.baseoperate.get_name(self.yaml.get_elementinfo(i)).click() elif self.yaml.get_findtype(i) == ’id’: self.baseoperate.get_id(self.yaml.get_elementinfo(i)).click() elif self.yaml.get_findtype(i) == ’xpath’: self.baseoperate.get_xpath(self.yaml.get_elementinfo(i)).click() elif self.yaml.get_findtype(i) == ’ids’: self.baseoperate.get_ids(self.yaml.get_elementinfo(i))[self.yaml.get_index(i)].click() elif self.yaml.get_operate_type(i) == ’send_keys’: if self.yaml.get_findtype(i) == ’text’: self.baseoperate.get_name(self.yaml.get_elementinfo(i)).send_keys(self.yaml.get_send_content(i)) elif self.yaml.get_findtype(i) == ’id’: self.baseoperate.get_id(self.yaml.get_elementinfo(i)).send_keys(self.yaml.get_send_content(i)) elif self.yaml.get_findtype(i) == ’xpath’: self.baseoperate.get_xpath(self.yaml.get_elementinfo(i)).send_keys(self.yaml.get_send_content(i)) elif self.yaml.get_findtype(i) == ’ids’: self.baseoperate.get_ids(self.yaml.get_elementinfo(i))[self.yaml.get_index(i)].send_keys(self.yaml.get_send_content(i)) elif self.yaml.get_operate_type(i) == ’back’: for n in range(self.yaml.get_backtimes(i)): self.baseoperate.back() elif self.yaml.get_operate_type(i) == ’swipe_up’: for n in range(self.yaml.get_backtimes(i)): self.baseoperate.swipe_up() def back_home(self): ’’’ 返回至工作臺(tái) :return: ’’’ self.baseoperate.page(’工作臺(tái)’)

公共部分的代碼就介紹這么多,在編寫這個(gè)框架的時(shí)候,大部分精力都花在這部分,所以個(gè)人覺得還是值得好好研究的

Page部分

page部分是最小用例集,一個(gè)模塊一個(gè)文件夾,以客戶為例,目前寫了兩個(gè)用例,一個(gè)新增,一個(gè)排序,文件如下:

python+appium+yaml移動(dòng)端自動(dòng)化測試框架實(shí)現(xiàn)詳解

代碼如下,非常的簡潔,

import sysreload(sys)sys.setdefaultencoding(’utf8’)import codecs,osfrom public.Operate import Operatefrom public.GetYaml import getyaml PATH = lambda p: os.path.abspath( os.path.join(os.path.dirname(__file__), p))yamlpath = PATH('../../testyaml/cm/cm-001addcm.yaml') class AddcmPage: def __init__(self,driver): self.path = yamlpath self.driver = driver self.operate = Operate(self.path,self.driver) def operateap(self): self.operate.check_operate_type() def home(self): self.operate.back_home()

運(yùn)行用例

這部分用了unittest,運(yùn)行所有測試用例和生成報(bào)告。一個(gè)模塊一個(gè)用例,以客戶為例:CmTest.py

from page.cm.CmAddcmPage import AddcmPagefrom page.cm.CmSortcmPage import SortcmPage from public.GetDriver import mydriverdriver = mydriver() import unittest,timeclass Cm(unittest.TestCase): def test_001addcm(self): ’’’ 新增客戶 :return: ’’’ add = AddcmPage(driver) add.operateap() add.home() def test_002sortcm(self): ’’’ 客戶排序 :return: ’’’ sort = SortcmPage(driver) sort.sortlist() sort.home() def test_999close(self): driver.quit() time.sleep(10) if __name__ == '__main__': unittest.main()

首先從page層將需要運(yùn)行的用例都import進(jìn)來,然后用unittest運(yùn)行即可。如果想要運(yùn)行所有的測試用例,需要用到runtest.py

import time,osimport unittestimport HTMLTestRunnerfrom testcase.CmTest import Cm def testsuit(): suite = unittest.TestSuite() suite.addTests([unittest.defaultTestLoader.loadTestsFromTestCase(Cm), ]) # runner = unittest.TextTestRunner(verbosity=2) # runner.run(suite) now=time.strftime('%y-%m-%d-%H-%M-%S') PATH = lambda p: os.path.abspath( os.path.join(os.path.dirname(__file__), p) ) dirpath = PATH('./results/waiqin365-') filename=dirpath + now +’result.html’ fp=open(filename,’wb’) runner=HTMLTestRunner.HTMLTestRunner(stream=fp,title=’waiqin365 6.0.6beta test result’,description=u’result:’) runner.run(suite) fp.close() if __name__ =='__main__': testsuit()

這邊的思路差不多,也是先導(dǎo)入再裝入suite即可

總結(jié)

就目前而言,暫時(shí)算是實(shí)現(xiàn)了數(shù)據(jù)與用例的分離,但是yaml的編寫要求較高,不能格式上出錯(cuò)。同時(shí)也有一些其他可以優(yōu)化的地方,如:

對(duì)彈窗的判斷 斷開后重連機(jī)制 失敗后重跑機(jī)制

到此這篇關(guān)于python+appium+yaml移動(dòng)端自動(dòng)化測試框架實(shí)現(xiàn)詳解的文章就介紹到這了,更多相關(guān)python appium yaml 自動(dòng)化測試 內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Python 編程
相關(guān)文章:
主站蜘蛛池模板: 新版天堂资源中文在线 | 在线免费观看国产视频 | 国内精品福利在线视频 | 亚洲精品一区二区三区第四页 | 在线满18网站观看视频 | 久久精品国产欧美日韩99热 | 在线综合+亚洲+欧美中文字幕 | 国产成人99精品免费观看 | 亚洲免费区 | 亚洲国产精品一区二区第四页 | 国产日韩在线观看视频 | 亚洲免费网站在线观看 | 久久91精品牛牛 | 精品久久在线 | 看国产一级毛片 | 成年女人毛片免费观看中文w | 免费一级肉体全黄毛片 | 青青热久久国产久精品秒播 | 婷婷的久久五月综合先锋影音 | 男女晚上爱爱的视频在线观看 | 国产精品久久久久久一级毛片 | 大陆老头xxxxxhd | 视频二区 中文字幕 欧美 | 日韩在线观看不卡 | 日本成本人视频 | 亚洲第一页在线播放 | 精品成人在线视频 | 成人国产精品毛片 | 欧产日产国产精品精品 | 亚洲综合国产一区二区三区 | 国产精品99精品久久免费 | 久久88综合| 最新国产美女一区二区三区 | 亚洲欧美精品久久 | 9久9久女女热精品视频免费观看 | 成年女人看片免费视频播放器 | 私人毛片免费高清影视院丶 | 窝窝午夜精品一区二区 | 澳门一级毛片手机在线看 | 欧美在线视频一区二区 | 狠狠色噜狠狠狠狠色综合久 |