之前已经发过一个,许多人给提了很宝贵的意见,根据大家的意见和自己的一点思考,对原来的框架进行了一点修改,这里给大家分享一下,还是请各位看完后多多提意见。
大体的结构没有太大的变化,这里附上原帖地址 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.修改了注释风格
下面仔细说一下
这个借鉴了 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 方法,现在是使用了 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 的配置文件,而是直接写在的代码中
这里也是借鉴了 xushizhao 的帖子,原帖地址如下 https://testerhome.com/topics/2937
为什么要这样做我就不多说,原帖里都说了,代码如下:
1.element.xml
与原帖不同的是我在 element 标签外面添加了一个 activity 标签,这样就可以不必要同个标签配置多次了。
<activity name = "GuideActivity"><!--activity名称-->
<element name="welcome"> <!-- 元素对象 -->
<name>Welcome</name><!-- 元素名称 -->
<type>RelativeLayout</type><!-- 元素类型 input/button -->
<pathtype>ID</pathtype><!-- 获取元素的模式 ID/XPATH/CLASSNAME/NAME-->
<pathvalue>ag_ll_dotlayout</pathvalue><!-- 元素定位路径 -->
</element>
</activity >
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()
@user1trized(
*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 文件里面开启 server,识别安装软件,后来发现自己的能力有限,要考虑的东西有点多,后来放弃了,改在 py 文件里面完成,然后仅在 bat 文件里面调用。
ECHO START INSTALL
F:
cd F:\testApp01
start pythonw testSet\init.py
ECHO END INSTALL
PAUSE
1.生成的报告不太满意,目前还是自己实现的,不知道各位有什么好的推荐?
2.异常机制依旧没有完善的太好,继续努力。
3.论坛里面有太多好帖子了,感觉大神的分享。
4.希望大家在看完帖子后可以留下你的意见,感谢!!!