前言
之前已经发过一个,许多人给提了很宝贵的意见,根据大家的意见和自己的一点思考,对原来的框架进行了一点修改,这里给大家分享一下,还是请各位看完后多多提意见。
结构
大体的结构没有太大的变化,这里附上原帖地址 https://testerhome.com/topics/3460
修改的地方有以下几个:
1.在testSet下增加了一个bsns文件夹,里面有bsnsCommon.py;element.xml;TestCase.xls3个文件夹
2.common里面增加AppiumServer.py;将myPhone.py变为init.py
3.增加了autoRun.bat和install.bat
修改处
1.讲AppiumServer从run.py中抽离出来,封装成了AppiumServer.py
2.弃用自己写的Log方法,使用了python自带的logging
3.讲element的路径配置进了element.xml中
4.实现了测试数据参数化
5.做成了bat文件调用run.py
6.修改了注释风格
下面仔细说一下
AppiumServer
这个借鉴了cosyman以前发过的帖子,原帖地址 https://testerhome.com/topics/1864
总结而言就是原先用线程做的现在改成了进程。代码如下:
class AppiumServer:
def __init__(self):
global appiumPath, baseUrl
appiumPath = readConfigLocal.getConfigValue("appiumPath")
baseUrl = readConfigLocal.getConfigValue("baseUrl")
def startServer(self):
"""start the appium server
:return:
"""
cmd = self.getCmd()
t1 = runServer(cmd)
p = Process(target=t1.start())
p.start()
def stopServer(self):
"""stop the appium server
:return:
"""
#kill myServer
os.system('taskkill /f /im node.exe')
def reStartServer(self):
"""reStart the appium server
:arg:
:return:
"""
self.stopServer()
self.startServer()
def isRunnnig(self):
"""Determine whether server is running
:return:True or False
"""
response = None
url = baseUrl+"/status"
try:
response = urllib.request.urlopen(url, timeout=5)
if str(response.getcode()).startswith("2"):
return True
else:
return False
except URLError:
return False
finally:
if response:
response.close()
def getCmd(self):
"""get the cmd of start appium server
:return:cmd
"""
rootDirectory = appiumPath[:2]
startCMD = "node node_modules\\appium\\bin\\appium.js"
cmd =rootDirectory+"&"+"cd "+appiumPath+"&"+startCMD
return cmd
import threading
class runServer(threading.Thread):
def __init__(self, cmd):
threading.Thread.__init__(self)
self.cmd = cmd
def run(self):
os.system(self.cmd)
if __name__ == "__main__":
oo = AppiumServer()
oo.startServer()
Log
原先是自己写的log方法,现在是使用了python自带的logging,部分代码如下:
self.logger = logging.getLogger()
self.logger.setLevel(logging.INFO)
#create handler,write log
fh = logging.FileHandler(os.path.join(logPath, "outPut.log" ))
#Define the output format of formatter handler
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
self.logger.addHandler(fh)
这里我并没有使用logging的配置文件,而是直接写在的代码中
element.xml
这里也是借鉴了xushizhao的帖子,原帖地址如下 https://testerhome.com/topics/2937
为什么要这样做我就不多说,原帖里都说了,代码如下:
1.element.xml
与原帖不同的是我在element标签外面添加了一个activity标签,这样就可以不必要同个标签配置多次了。
Welcome
RelativeLayout
ID
ag_ll_dotlayout
2.调用方法
activity = {}
def setXml():
"""
get the xml file's value
:use:
a = getXml(path)
print(a.get(".module.GuideActivity").get("skip").get("type"))
:param: xmlPath
:return:activity
"""
if len(activity) == 0:
xmlPath = os.path.join(readConfig.prjDir, "testSet\\bsns", "element.xml")
# open the xml file
per = ET.parse(xmlPath)
allElement = per.findall('activity')
for firstElement in allElement:
activityName = firstElement.get("name")
element = {}
for secondElement in firstElement.getchildren():
elementName = secondElement.get("name")
elementChild = {}
for thirdElement in secondElement.getchildren():
elementChild[thirdElement.tag] = thirdElement.text
element[elementName] = elementChild
activity[activityName] = element
def getElDict(activityName, elementName):
"""
According to the activityName and elementName get element
:param activityNmae:
:param elementName:
:return:
"""
setXml()
elementDict = activity.get(activityName).get(elementName)
return elementDict
class element:
def __init__(self, activutyName, elementName):
global driver
driver = myDriver.GetDriver()
self.activutyNmae = activutyNmae
self.elementName = elementName
elementDict = getElDict(self.activutyNmae, self.elementName)
self.pathtype = elementDict.get("pathtype")
self.pathvalue = elementDict.get("pathvalue")
def isExist(self):
"""
To determine whether an element is exits
:return: TRUE or FALSE
"""
try:
if self.pathtype == "ID":
driver.find_element_by_id(self.pathvalue)
if self.pathtype == "CLASSNAME":
driver.find_element_by_class_name(self.pathvalue)
if self.pathtype == "XPATH":
driver.find_element_by_xpath(self.pathvalue)
if self.pathtype == "NAME":
driver.find_element_by_name(self.pathvalue)
except NoSuchElementException:
return False
return True
def doesExist(self):
"""
To determine whether an element is exits
:return:
"""
i = 1
while not self.isExist():
sleep(1)
i = i+1
if i >= 10:
return False
else:
return True
def get(self):
"""
get one element
:return:
"""
if self.doesExist():
if self.pathtype == "ID":
element = driver.find_element_by_id(self.pathvalue)
return element
if self.pathtype == "CLASSNAME":
element = driver.find_element_by_class_name(self.pathvalue)
return element
if self.pathtype == "XPATH":
element = driver.find_element_by_xpath(self.pathvalue)
return element
if self.pathtype == "NAME":
element = driver.find_element_by_name(self.pathvalue)
return element
else:
return None
def gets(self, index):
"""
get one element in elementList
:return:
"""
if self.doesExist():
if self.pathtype == "ID":
elements = driver.find_elements_by_id(self.pathvalue)
return elements[index]
if self.pathtype == "CLASSNAME":
elements = driver.find_elements_by_class_name(self.pathvalue)
return elements[index]
if self.pathtype == "XPATH":
elements = driver.find_elements_by_xpath(self.pathvalue)
return elements[index]
if self.pathtype == "NAME":
elements = driver.find_elements_by_name(self.pathvalue)
return elements[index]
return None
else:
return None
def click(self):
"""
click element
:return:
"""
try:
el = self.get()
el.click()
except AttributeError:
raise
def clicks(self, index):
"""
click element
:return:
"""
try:
el = self.gets(index)
el.click()
except AttributeError:
raise
def sendKey(self,values):
"""
input the key
:return:
"""
try:
el = self.get()
el.clear()
el.send_keys(values)
except AttributeError:
raise
def sendKeys(self, index, values):
"""
input the key
:return:
"""
try:
el = self.gets(index)
el.clear()
el.send_keys(values)
except AttributeError:
raise
def getAttribute(self, attribute):
"""
get the element attribute
:param attribute:
:return:value
"""
el = self.get()
value = el.get_attribute(attribute)
return value
根据anctivityName 和 elementName获取element,使用的时候可以这样用:element(anctivityName ,elementName).click()
测试数据参数化
这里我是使用了ParamUnittest,官网地址如下大家可以咨询下载:https://pypi.python.org/pypi/ParamUnittest#downloads
将测试数据配置到excel里面,然后读取。代码如下:
读取excel
import xlrd
cls = []
def getXLS(sheetName):
"""
get the value in excel
:param sheetName
:return:cls
"""
if len(cls) == 0:
xlsPath = os.path.join(readConfig.prjDir, "testSet\\bsns", "TestCase.xls")
#read the excel
data = xlrd.open_workbook(xlsPath)
#get the sheet
table = data.sheet_by_name(sheetName)
nrows = table.nrows
for i in range(nrows):
if table.row_values(i)[0] != 'userName':
cls.append(table.row_values(i))
return cls
ParamUnittest的使用
loginCls = getLoginCls()
@paramunittest.parametrized(
*loginCls
)
class TestBar(paramunittest.ParametrizedTestCase):
def setParameters(self, userName,password,result):
self.userName = userName
self.password = password
self.result = result
def runTest(self):
print(self.userName, self.password, self.result)
ParamUnittest的例官网里面有好多,大家可以自己去研究。
bat
本来是想在bat文件里面开启server,识别安装软件,后来发现自己的能力有限,要考虑的东西有点多,后来放弃了,改在py文件里面完成,然后仅在bat文件里面调用。
ECHO START INSTALL
F:
cd F:\testApp01
start pythonw testSet\init.py
ECHO END INSTALL
PAUSE
总结
1.生成的报告不太满意,目前还是自己实现的,不知道各位有什么好的推荐?
2.异常机制依旧没有完善的太好,继续努力。
3.论坛里面有太多好帖子了,感觉大神的分享。
4.希望大家在看完帖子后可以留下你的意见,感谢!!!