自动化测试-数据驱动实践(登录)
测试流程:
1、账号密码手动写入Excel中
2、使用ddt读取Excel中的账号密码
3、使用unittest进行单元测试,登录公司某个系统
4、断言是否用例是否执行成功(登录成功判断页面中是否有“退出”,登录失败的判断页面提示是否正确)
5、最后生成HTML测试报告
在本地磁盘D:\test\DataDrivenTesting目录中新建一个“登录测试.xlsx”,工作表名为“账号密码”,内容如下:
序号 账号 密码 期望结果
1 chenyl1 a123456 退出
2 chenyl2 a123456 退出
3 chenyl3 a123456 退出
4 chenyl4 a123456 退出
5 chenyl4 请输入密码
6 a123456 请输入用户名
7 请输入用户名
8 abc1234 a123456 该用户不存在
9 chenyl1 xx112233 密码错误
10 acbd123 1123aaxx 该用户不存在
在PyCharm中创建MyLoginProject的Python工程,并在工程下创建以下文件:ExcelUtil.py ,ReportTemplate.py,MyLoginDataDrivenByExcel.py
ExcelUtil.py文件用于编写读取Excel的脚本,具体内容如下:
#encoding=utf-8 from openpyxl import load_workbook class ParseExcel(object): def __init__(self, excelPath, sheetName): # 将要读取的excel加载到内存 self.wb = load_workbook(excelPath) # 通过工作表名称获取一个工作表对象 self.sheet = self.wb.get_sheet_by_name(sheetName) # 获取工作表中存在数据的区域的最大行号 self.maxRowNum = self.sheet.max_row def getDatasFromSheet(self): # 用于存放从工作表中读取出来的数据 dataList = [] for line in self.sheet.rows: # 遍历工作表中数据区域的每一行, # 并将每行中各个单元格的数据取出存于列表tmpList中, # 然后再将存放一行数据的列表添加到最终数据列表dataList中 tmpList = [] #如果单元格为空,则在列表中插入一个为空的unicode字符串,以免输入账号密码时报错 if line[1].value == None: tmpList.append(u"") else: tmpList.append(line[1].value) if line[2].value == None: tmpList.append(u"") else: tmpList.append(line[2].value) tmpList.append(line[3].value) dataList.append(tmpList) # 将获取工作表中的所有数据的迭代对象返回 # 因为工作表中的第一行是标题行,所以需要去掉 return dataList[1:] if __name__ == '__main__': excelPath = u'D:\\test\\DataDrivenTesting\\登录测试.xlsx' sheetName = u"账号密码" pe = ParseExcel(excelPath, sheetName) print pe.getDatasFromSheet() for i in pe.getDatasFromSheet(): print i[0],type(i[0]) #i[1],i[2]
文件ReportTemplate.py用于生成自定义HTML测试报告,具体内容如下:
# encoding=utf-8 def htmlTemplate(url, trData): htmlStr = u'''<!DOCTYPE HTML> <html> <head><meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> <title>单元测试报告</title> <style> body { width: 80%; /*整个body区域占浏览器的宽度百分比*/ margin: 40px auto; /*整个body区域相对浏览器窗口摆放位置(左右,上下)*/ font-weight: bold; /*整个body区域的字体加粗*/ font-family: 'trebuchet MS', 'Lucida sans', SimSun; /*表格中文字的字体类型*/ font-size: 18px; /*表格中文字字体大小*/ color: #000; /*整个body区域字体的颜色*/ } table { *border-collapse: collapse; /*合并表格边框*/ border-spacing: 0; /*表格的边框宽度*/ width: 100%; /*整个表格相对父元素的宽度*/ } .tableStyle { /*border: solid #ggg 1px;*/ border-style: outset; /*整个表格外边框样式*/ border-width: 2px; /*整个表格外边框宽度*/ /*border: 2px;*/ border-color: blue; /*整个表格外边框颜色*/ } .tableStyle tr:hover { background: rgb(173,216,230); /*鼠标滑过一行时,动态显示的颜色146,208,80*/ } .tableStyle td,.tableStyle th { border-left: solid 1px rgb(146,208,80); /*表格的竖线颜色*/ border-top: 1px solid rgb(146,208,80); /*表格的横线颜色 */ padding: 15px; /*表格内边框尺寸*/ text-align: center; /*表格内容显示位置*/ } .tableStyle th { padding: 15px; /*表格标题栏,字体的尺寸*/ background-color: rgb(146,208,80); /*表格标题栏背景颜色*/ /*表格标题栏设置渐变颜色*/ background-image: -webkit-gradient(linear, left top, left bottom, from(#92D050), to(#A2D668)); /*rgb(146,208,80)*/ } </style> </head> <body> <center><h1>测试报告</h1></center><br /><br /><br /> <table class="tableStyle"> <thead> <tr> <th>No</th> <th>Username</th> <th>Password</th> <th>Assert Words</th> <th>Start Time</th> <th>Waste Time(s)</th> <th>Status</th> </tr> </thead>''' endStr = u''' </table> </body> </html>''' # 拼接完整的测试报告HTML页面代码 html = htmlStr + u"<b>测试网址: " + url + u"</b>" + trData + endStr #print html # 生成.html文件 with open(u"D:\\test\\DataDrivenTesting\\testTemplate.html", "w") as fp: fp.write(html.encode("gbk"))
MyLoginDataDrivenByExcel.py用于编写数据驱动测试脚本,具体内容如下:
#encoding=utf-8 from selenium import webdriver import unittest,time,os import logging,traceback import ddt from ExcelUtil import ParseExcel from ReportTemplate import htmlTemplate from selenium.common.exceptions import NoSuchElementException # 初始化日志对象 logging.basicConfig( # 日志级别 level=logging.INFO, # 日志格式 # 时间、代码所在文件名、代码行号、日志级别名字、日志信息 format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', # 打印日志的时间 datefmt='%a, %Y-%m-%d %H:%M:%S', # 日志文件存放的目录(目录必须存在)及日志文件名 filename='D:\\test\\DataDrivenTesting\\report.log', # 打开日志文件的方式 filemode='w' ) excelPath = u"D:\\test\\DataDrivenTesting\\登录测试.xlsx" sheetName = u"账号密码" #ParseExcel类的实例对象 excel = ParseExcel(excelPath,sheetName) @ddt.ddt class TestDemo(unittest.TestCase):
#公司地址保密,使用xxx代替 url = "xxx" no = 0 @classmethod def setUpClass(cls): # 整个测试过程只被调用一次 TestDemo.trStr = "" def setUp(self): self.driver = webdriver.Ie(executable_path="D:\\IEDriverServer") status = None # 用于存放测试结果状态,失败'fail',成功'pass' flag = 0 # 数据驱动测试结果的标志,失败置0,成功置1 TestDemo.no += 1 @ddt.data(*excel.getDatasFromSheet()) def test_dataDrivenByFile(self, data): # 决定测试报告中状态单元格中内容的颜色 flagDict = {0: 'red', 1: '#00AC4E'} # 访问系统 self.driver.get(TestDemo.url) # 将浏览器窗口最大化 self.driver.maximize_window() #print data # 读取Excel中的账号密码及期望结果 username,password, expectdata = tuple(data) # 设置隐式等待时间为10秒 self.driver.implicitly_wait(10) try: # 获取当前的时间戳,用于后面计算查询耗时用 start = time.time() # 获取当前时间的字符串,表示测试开始时间 startTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) # 找到用户名输入框,并输入测试数据 self.driver.find_element_by_id("username").send_keys(username) # 找到密码输入框,并输入测试数据 self.driver.find_element_by_id("password").send_keys(password) # 找到登录按钮,并点击 self.driver.find_element_by_id("button").click() time.sleep(5) # 断言期望结果是否出现在页面源代码中 self.assertTrue(expectdata in self.driver.page_source) except NoSuchElementException, e: logging.error(u"查找的页面元素不存在,异常堆栈信息:" + str(traceback.format_exc())) status = 'fail' flag = 0 except AssertionError, e: logging.info(u"登录账号:“%s”,期望“%s”,失败" % (username, expectdata)) status = 'fail' flag = 0 except Exception, e: logging.error(u"未知错误,错误信息:" + str(traceback.format_exc())) status = 'fail' flag = 0 else: logging.info(u"登录账号:“%s”,期望“%s”通过" % (username, expectdata)) status = 'pass' flag = 1 # 计算耗时,从将测试数据输入到输入框中到断言期望结果之间所耗时 wasteTime = time.time() - start - 5 # 减去强制等待的3秒 # 每一组数据测试结束后,都将其测试结果信息插入表格行 # 的HTML代码中,并将这些行HTML代码拼接到变量trStr变量中, # 等所有测试数据都被测试结束后,传入htmlTemplate()函数中 # 生成完整测试报告的HTML代码 TestDemo.trStr += u''' <tr> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td>%.2f</td> <td style="color:%s">%s</td> </tr><br />''' % (TestDemo.no, username,password, expectdata, startTime, wasteTime, flagDict[flag], status) def tearDown(self): self.driver.quit() @classmethod def tearDownClass(cls): # 写自定义的html测试报告 # 整个测试过程只被调用一次 htmlTemplate(TestDemo.url, TestDemo.trStr) if __name__ == '__main__': unittest.main()