最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時間:2020年11月24日 10:32:18   作者:愛碼哥  
這篇文章主要介紹了python+appium+yaml移動端自動化測試框架實現(xiàn)詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

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

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

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

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

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

results 存放測試報告及失敗截圖

logs 存放日志

testcase 存放測試用例runtest.py 運行所有測試用例

yaml格式介紹

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

element_info:定位元素信息

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

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

上面三個必填,operate_type必填!!!!!!

send_content:send_keys 時用到

index:ids時用到

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

testinfo:
 - id: cm001
  title: 新增終端門店
  execute: 1
testcase:
 -
  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

代碼部分

公共部分

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

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

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

#coding=utf-8
#author='Shichao-Dong'
 
import sys
reload(sys)
sys.setdefaultencoding('utf8')
import yaml
import 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']

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

#coding=utf-8
#author='Shichao-Dong'
 
from logs import log
import random,time
import platform
import os
from 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):
  """
  啟動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: 啟動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.py
platformName、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 WebDriverWait
from logs import log
import os
import time
 
'''
一些基礎(chǔ)操作:滑動、截圖、點擊頁面元素等
'''
 
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):
  '''
  向上滑動
  :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):
  '''
  判斷頁面是否存在某個元素
  :param name: text
  :return:
  '''
  findname = "http://*[@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 = "http://*[@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 = "http://*[@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 = "http://*[@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("http://*[@text='工作臺']")
     self.driver.implicitly_wait(2)
     break
    except:
     os.popen("adb shell input keyevent 4")

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

#coding=utf-8
#author='Shichao-Dong'
 
from GetYaml import getyaml
from 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就是返回,暫時就三種
  上面三個必填,operate_type必填!!!!!!
  send_content:send_keys 時用到
  index:ids時用到
  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):
  '''
  返回至工作臺
  :return:
  '''
  self.baseoperate.page('工作臺')

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

Page部分

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

代碼如下,非常的簡潔,

import sys
reload(sys)
sys.setdefaultencoding('utf8')
import codecs,os
from public.Operate import Operate
from 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()

運行用例

這部分用了unittest,運行所有測試用例和生成報告。
一個模塊一個用例,以客戶為例:CmTest.py

from page.cm.CmAddcmPage import AddcmPage
from page.cm.CmSortcmPage import SortcmPage
 
 
from public.GetDriver import mydriver
driver = mydriver()
 
import unittest,time
class 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層將需要運行的用例都import進(jìn)來,然后用unittest運行即可。
如果想要運行所有的測試用例,需要用到runtest.py

import time,os
import unittest
import HTMLTestRunner
from 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é)

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

  • 對彈窗的判斷
  • 斷開后重連機制
  • 失敗后重跑機制

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

相關(guān)文章

  • python中torch.nn.identity()方法詳解

    python中torch.nn.identity()方法詳解

    今天看源碼時遇到的這個恒等函數(shù),就如同名字那樣占位符,并沒有實際操作,下面這篇文章主要給大家介紹了關(guān)于python中torch.nn.identity()方法的相關(guān)資料,需要的朋友可以參考下
    2022-03-03
  • 淺談一下python中threading模塊

    淺談一下python中threading模塊

    這篇文章主要介紹了一下python中threading模塊,threading提供了一個比thread模塊更高層的API來提供線程的并發(fā)性。這些線程并發(fā)運行并共享內(nèi)存,需要的朋友可以參考下
    2023-04-04
  • Python 分享10個PyCharm技巧

    Python 分享10個PyCharm技巧

    這篇文章主要介紹了Python 分享10個PyCharm技巧,今天要跟大家分享幾個PyCharm小技巧,幫助大家提升工作效率!,需要的朋友可以參考下
    2019-07-07
  • python 將numpy維度不同的數(shù)組相加相乘操作

    python 將numpy維度不同的數(shù)組相加相乘操作

    這篇文章主要介紹了python 將numpy維度不同的數(shù)組相加相乘操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-03-03
  • Python利用Charles 實現(xiàn)全部自動答題思路流程分析

    Python利用Charles 實現(xiàn)全部自動答題思路流程分析

    這篇文章主要介紹了Python利用Charles 實現(xiàn)全部自動答題思路流程分析,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-08-08
  • python GUI實現(xiàn)小球滿屏亂跑效果

    python GUI實現(xiàn)小球滿屏亂跑效果

    這篇文章主要為大家詳細(xì)介紹了python GUI實現(xiàn)小球滿屏亂跑效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • python3實現(xiàn)將json對象存入Redis以及數(shù)據(jù)的導(dǎo)入導(dǎo)出

    python3實現(xiàn)將json對象存入Redis以及數(shù)據(jù)的導(dǎo)入導(dǎo)出

    這篇文章主要介紹了python3實現(xiàn)將json對象存入Redis以及數(shù)據(jù)的導(dǎo)入導(dǎo)出,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-07-07
  • python基礎(chǔ)之文件操作

    python基礎(chǔ)之文件操作

    這篇文章主要介紹了python文件操作,實例分析了Python中返回一個返回值與多個返回值的方法,需要的朋友可以參考下
    2021-10-10
  • Python四大金剛之集合詳解

    Python四大金剛之集合詳解

    這篇文章主要介紹了Python的集合,小編覺得這篇文章寫的還不錯,需要的朋友可以參考下,希望能夠給你帶來幫助
    2021-10-10
  • 純python實現(xiàn)機器學(xué)習(xí)之kNN算法示例

    純python實現(xiàn)機器學(xué)習(xí)之kNN算法示例

    本篇文章主要介紹了純python實現(xiàn)機器學(xué)習(xí)之kNN算法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-03-03

最新評論

思南县| 土默特左旗| 台中县| 桃源县| 竹溪县| 永福县| 廉江市| 汤原县| 平泉县| 合阳县| 绿春县| 富顺县| 南通市| 乐东| 乐东| 铁力市| 公主岭市| 桃江县| 家居| 南澳县| 凤阳县| 乌兰浩特市| 恩施市| 大英县| 夏河县| 石阡县| 溧阳市| 宾川县| 玉屏| 随州市| 宁化县| 公安县| 明溪县| 鹿泉市| 宾川县| 黑河市| 阳泉市| 闵行区| 积石山| 黔西县| 涿鹿县|