1.po模型概述
我們進行自動化測試時,如果把代碼都寫在一個腳本中,代碼的可讀性會變差,且後期代碼維護也麻煩,最好的想法就是測試對象和測試用例可以分離,可以很快定位問題,代碼可讀性高,也比較容易理解。這裏推薦大家在自動化框架中加入PO模型思想,那什麼是PO模型呢?
所謂的PO就是page object,通俗解釋一下就是每個頁面當成一個對象,給這些頁面寫一個類,主要就是完成元素定位和業務操作。
而在實際的用例書寫中,你就會發小,UI自動化的操作是比較固定的,常用的方法比較固定(點擊、傳入鍵值、截圖等),而不同的是所操作的元素,這樣的話我們只需要傳入不同的元素即可。
詳情請點擊 https://study.163.com/course/introduction/1209833813.htm 查看
整體架構如下:
2.封裝file.py
file.py中存放的是一些公共的方法,比如:讀取配置文件、獲取元素、加載用例等等
import re
import os
import logging
import logging.config
CON_LOG=os.path.abspath((os.path.dirname((os.path.dirname(__file__))))+'/config/log.conf')
logging.config.fileConfig(CON_LOG)
logging=logging.getLogger()
import configparser
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import TimeoutException
import time
from datetime import datetime
import warnings
warnings.simplefilter("ignore", ResourceWarning)
import subprocess
class ReadTxt():
def __init__(self,file_path=None):
if file_path==None:
self.file_path=os.path.abspath((os.path.dirname(os.path.dirname(__file__)))+'/config/app_info.txt')
else:
self.file_path=file_path
def get_appinfo(self,value): #讀取app的配置文件app_info.txt
logging.info("讀取app_info.txt文件")
with open(self.file_path) as f:
lines=f.readlines()
for line in lines:
key_value=re.split('=',line)
if key_value[0]==value:
return key_value[1].replace("\n","")
else:
continue
class ReadIni(): #讀取ini文件的類
def __init__(self,file_path=None):
if file_path==None:
self.file_path=os.path.abspath((os.path.dirname(os.path.dirname(__file__)))+'/config/page.ini')
else:
self.file_path=file_path
self.data=self.read_ini()
def read_ini(self):
read_ini=configparser.ConfigParser()
read_ini.read(self.file_path,encoding="utf-8-sig")
return read_ini
def get_value(self,session,key):
logging.info("get value: ["+session +"] - [" + key +"] from "+ self.file_path )
try:
value=self.data.get(session,key)
except:
logging.error("獲取元素出現了錯誤,請檢查傳入的session和key是否正確:session: "+session+" key:"+key)
value=None
return value
read_ini=ReadIni() #實例化一個ReadIni類,在GetByLocal類中使用
#定義一個獲取元素的類
class GetByLoacl():
def __init__(self,driver):
self.driver=driver
def getScreenShot(self,text): #封裝截圖函數
logging.info("開始截圖")
dt=datetime.now()
now_time=dt.strftime("%Y_%m_%d_%H_%M_%S")
image_file=os.path.dirname(os.path.dirname(__file__))+"\\Result\\Screenshots\\%s_%s.png" %(now_time,text)
logging.info(image_file)
self.driver.get_screenshot_as_file(image_file)
def no_find_element(self,section,key,value):
text="["+section+"]_["+key+"]_"+value+"沒有找到"
logging.error(text)
text1=section+"_"+key+"_沒有找到元素"
self.getScreenShot(text1)
def get_element(self,session,key,wait=10):
local=read_ini.get_value(session,key)
if local is None:
logging.error("沒有找到元素")
self.driver.get_screenshot_as_file("1.png")
return None
by=local.split('>')[0]
element_value=local.split('>')[1]
if by=='id':
#使用id定位元素
try:
element=WebDriverWait(self.driver,wait).until(lambda x:x.find_element_by_id(element_value))
except TimeoutException:
self.no_find_element(session,key,element_value)
return None
else:
return element
elif by=='xpath': #使用xpath定位
#self.getScreenShot("測試一下封裝的截圖方法")
#self.no_find_element(session,key,element_value)
try:
element=WebDriverWait(self.driver,wait).until(lambda x:x.find_element_by_xpath(element_value))
except TimeoutException:
self.no_find_element(session, key, element_value)
return None
else:
return element
elif by=='ids':
local_num=local.split('>')[2]
try:
local_num=int(local_num)
element=WebDriverWait(self.driver,wait).until(lambda x:x.find_elements_by_id(element_value)[local_num])
except TimeoutException:
self.no_find_element(session, key, element_value)
return None
else:
return element
else:
logging.error("沒有找到這個查找元素的方法,請檢查get_by_local和page_ini文件,是否是配置文件寫錯,或者是沒有封裝該方法")
def get_files(path):
#該方法是用來加載用例的,返回用例的列表
logging.info("現在開始加載用例")
logging.info('get_files '+path)
f1=[]
f_list=os.listdir(path)
for i in f_list:
fulldirfile=os.path.join(path,i)
if os.path.isdir(fulldirfile): #如果全路徑是文件夾,跳過繼續處理
continue
else:
f1.append(path+"\\"+i)
text=str(len(f1)) + " cases in the path "+path
logging.info(text)
return f1
#print(f1)
#封裝一個函數,獲取測試報告的路徑,並且要加上時間戳
PRJPATH=os.getcwd()
def get_new_file(path=None):
now=time.strftime("%Y-%m-%d-%H_%M_%S",time.localtime(time.time()))
filename=PRJPATH
if path is None:
path='/report/'
else:
path='/'+path+'/'
filename=filename+path+'text report '+now +'.html'
logging.info("get_new_file "+filename)
if not os.path.exists(os.path.dirname(filename)):
os.makedirs(os.path.dirname(filename))
return filename
def get_new_dir(case): #這個是用來創建存放app日誌的文件的
now=time.strftime("%Y-%m-%d-%H_%M_%S",time.localtime(time.time()))
filename=PRJPATH
filename=filename+'/logs/'+os.path.basename(case)+'/'+now
logging.info("get_new_dir "+filename)
os.makedirs(filename)
logging.info('make a new dir')
return filename
def start_logcat(filename):
filename=filename+'/logcat.log'
logging.info("start logcat "+filename)
logcat_file=open(filename,'w')
ip=ReadTxt().get_appinfo('udid') #獲取設備的udid
logcmd="adb logcat -v threadtime"
logcmd=logcmd.replace('adb','adb -s '+ip)
proc=subprocess.Popen(logcmd,stdout=logcat_file,stderr=subprocess.PIPE)
return proc,filename
def end_logcat(proc):
logging.info("end logcat")
proc.terminate()
def read_case(path):
lines=open(path,encoding='utf-8',errors='ignore').readlines()
steps=[]
for l in lines:
ll=l.strip() #處理空格或者換行符
if len(ll)<2:
continue
if ll.startswith('#'):
continue
logging.info(ll)
d=ll.split('|')
steps.append(tuple(d))
return steps
if __name__=="__main__":
# logging.info("這個是測試一下日誌配置文件")
# path=os.path.dirname(os.path.dirname(__file__))
# print(path)
# logging.info("這是測試一下讀取ini文件")
# read_ini=ReadIni()
# result=read_ini.get_value('shouye','fabu')
# print(result)
dt = datetime.now()
now_time = dt.strftime("%Y_%m_%d_%H_%M_%S")
print(dt)
print(now_time)
get_files("D:\\Project_python\\Appium\\auto_case\\case")
get_new_file()
PRJPATH = os.getcwd()
print(PRJPATH)
case="D:\\Project_python\\Appium\\auto_case\\case\\test_fabu.py"
case_name = case.split('\\')[-1].split('.')[0]
print(case_name)
3.配置文件
配置文件config下有三個文件,一個是app_info.txt,存放的是app啓動信息;一個是log.conf,存放的是日誌的配置文件,一個啊page.ini,存放的是頁面元素的信息,直接把頁面元素放到這裏就可以了。
app_info.txt
platformName=Android
platformVersion=9.0
deviceName=HONOR9X
udid=GDB6R19718023173
appPackage=com.ss.android.article.news
appActivity=com.ss.android.article.news.activity.MainActivity
server=http://localhost:4723/wd/hub
log.conf
[loggers]
keys=root,infoLogger
[logger_root]
level=DEBUG
handlers=consoleHandler,fileHandler
[logger_infoLogger]
handlers=consoleHandler,fileHandler
qualname=infoLogger
propagate=0
[handlers]
keys=consoleHandler,fileHandler
[handler_consoleHandler]
class=StreamHandler
level=INFO
formatter=form02
args=(sys.stdout,)
[handler_fileHandler]
class=FileHandler
level=INFO
formatter=form01
args=('../Result/Logs/runlog.log', 'a+')
[formatters]
keys=form01,form02
[formatter_form01]
format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s
[formatter_form02]
format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s
page.ini
[shouye]
fabu=xpath>//*[@text="發佈"]
xiguanshipin=xpath>//*[@text="西瓜視頻"]
[fabupage]
caogaoxiang=xpath>//*[@text="草稿箱"]
4.封裝base_driver
base_driver.py中啓動app,其appium的參數是從config下的app_info.txt中讀取的
from appium import webdriver
import time
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
from public.file import ReadTxt
readtxt=ReadTxt() #導入讀取txt的類
import logging
def android_driver():
logging.info("開始啓動Android APP")
desired_caps={}
desired_caps['platformName']=readtxt.get_appinfo("platformName")
desired_caps['platformVersion']=readtxt.get_appinfo("platformVersion")
desired_caps['deviceName']=readtxt.get_appinfo("deviceName")
desired_caps['udid']=readtxt.get_appinfo("udid")
desired_caps['appPackage']=readtxt.get_appinfo("appPackage")
desired_caps['appActivity']=readtxt.get_appinfo("appActivity")
desired_caps['noReset']=True
driver=webdriver.Remote(readtxt.get_appinfo("server"),desired_caps)
time.sleep(10)
return driver
if __name__=='__main__':
driver=android_driver()
time.sleep(10)
try:
print("開始定位元素")
element=WebDriverWait(driver,10).until(lambda x:x.find_element_by_xpath('//*[@text="發佈1"]'))
except TimeoutException:
logging.error("這個出現了錯誤,超時了")
else:
logging.info("開始點擊操作")
element.click()
5.封裝po.py
po.py中,存放的是元素的操作邏輯
from base.base_driver import android_driver
import logging
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import TimeoutException
import sys
import time
from public.file import GetByLoacl
class pageobject():
def __init__(self):
self.driver=android_driver()
self.get_element=GetByLoacl(self.driver)
def go_home(self):
self.driver.start_activity("com.ss.android.article.news","com.ss.android.article.news.activity.MainActivity")
time.sleep(5)
def click_fabu(self):
logging.info("點擊發布按鈕")
element=self.get_element.get_element('shouye','fabu')
element.click()
def check_clici_fabu(self):
logging.info("現在開始檢查是否有草稿箱元素")
element=self.get_element.get_element("fabupage","caogaoxiang")
if element is None:
return False
else:
return True
if __name__=="__main__":
po=pageobject()
po.click_fabu()
result=po.check_clici_fabu()
if result==True:
logging.info("執行成功")
else:
logging.error("執行失敗")
6.封裝case.py
case.py是執行用例的入口
import sys
import unittest
import HTMLTestRunner
from PO.po import pageobject
import logging
import warnings
warnings.simplefilter("ignore",ResourceWarning)
class CaseTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.pog=pageobject()
logging.info("setup class")
def setUp(self):
logging.info("This is setup")
def test_001(self):
logging.info("開始測試點擊發布的功能")
self.pog.click_fabu()
self.assertTrue(self.pog.check_clici_fabu())
def test_002(self):
self.pog.go_home()
logging.info("在此測試一下發布功能")
self.pog.click_fabu()
self.assertTrue(self.pog.check_clici_fabu())
def tearDown(self):
logging.info("tearDown")
@classmethod
def tearDownClass(cls):
logging.info("This is teardownclass")
def get_suit():
logging.info("開始執行用例")
suite=unittest.TestSuite()
suite.addTest(CaseTest("test_001"))
suite.addTest(CaseTest("test_002"))
html_file="D:\\Project_python\\Appium\\Result\\Report\\report.html"
fp=open(html_file,'wb')
HTMLTestRunner.HTMLTestRunner(stream=fp).run(suite)
if __name__=="__main__":
logging.info("開始執行")
get_suit()
詳情請點擊 https://study.163.com/course/introduction/1209833813.htm 查看