标签:调用 with 动态获取 一件事 位置 method 二维数组 环境变量 std
一.自动化测试分类:
1.数据驱动:
根据数据(读取excel)来去测试的。
2.代码驱动:
测试用例都是写代码的。
3.关键字驱动:
UI自动化,根据封装好的工具,输入关键字来测试,有点傻瓜式测试。
二.自动化框架:可以理解为工具的集合。日常工作中,根据工作需求,实现某些功能,封装起来。或结合其他自动化工具。
三.举例:数据驱动自动测试框架:
自动化测试框架步骤:
1.获取用例
2.调用接口
3.校验结果
4.发送测试报告
5.异常处理
6.日志模块
码起来:【宗旨:一个函数只做一件事情】
提示:
1.用例文件的内容:
2.ATP文件的结构:
一.在common.py里写OpCase类,及get_case,my_request,check_res,write_excel,dataToDict函数。
1.get_case()函数:获取用例。获取用例中需要的数据:url,请求方式,请求数据及预期结果,放到cases list里
import xlrd from lib.log import atp_log class OpCase(object): def get_case(self,file_path):#获取用例的函数 cases = [] #存放所有的case if file_path.endswith(‘.xls‘) or file_path.endswith(‘.xlsx‘): #判断用例文件是否是excel try: book = xlrd.open_workbook(file_path) sheet = book.sheet_by_index(0) for i in range(1,sheet.nrows): row_data = sheet.row_values(i) #获取每行 cases.append(row_data[4:8]) #将用例中第5列至第9列截取到cases list中 atp_log.info(‘共读取%s条用例‘%(len(cases))) #读取用例的条数 self.file_path = file_path #在实例中将路径(文件名)定义,在后面write_excel()函数中不需要再传入该参数,可以直接用,否则需要在write_excel()函数中传入参数file_path except Exception as e: atp_log.error(‘【%s】用例获取失败,错误信息:%s‘%(file_path,e)) else: atp_log.error(‘用例文件不合法的,%s‘%file_path) return cases
2.my_request()及dataToDict()函数,调用接口。通过url,data请求获取返回的内容,其中获取的data需要先转成字典
import requests def my_request(self,url,method,data):#参数url,method,data method = method.upper() #传入参数有可能会有大小写,统一转成大写字母 data = self.dataToDict(data) #将获取的数据做处理,转成字典 try : if method==‘POST‘: #判断method的类型 res = requests.post(url,data).text #发送请求并转换成字典 elif method==‘GET‘: res = requests.get(url,params=data).text else: atp_log.warning(‘该请求方式暂不支持。。‘) #调用日志文件 res = ‘该请求方式暂不支持。。‘ except Exception as e: msg = ‘【%s】接口调用失败,%s‘%(url,e) atp_log.error(msg) res = msg return res #返回请求返回的内容 def dataToDict(self,data):#从excel表里获取的data格式:username=fancy,passwd=abc123456,把数据转成字典 res = {} data = data.split(‘,‘) for d in data: k,v = d.split(‘=‘) res[k]=v return res
3.check_res()函数,校验结果成功或失败。将从服务器获取的返回结果与excel表里的预期结果比较,是否一致,若一致返回“成功”并写入结果,否则失败。
首先了解从my_request里获取的返回内容的样式:
excel表里预期结果的样式:
思路:将my_request()函数里返回的res样式变为:
然后判断预期结果check是否在res返回的这个字典里。
具体实现如下:
def check_res(self,res,check): res = res.replace(‘": "‘,‘=‘).replace(‘": ‘,‘=‘) #两次替换,把res里返回的字典里所有的替换成=号(因为返回的Json串格式都是一样的) for c in check.split(‘,‘): #将预期结果里的以逗号分开 if c not in res: #判断预期结果里的list是否在返回结果res里 atp_log.info(‘结果校验失败,预期结果:【%s】,实际结果【%s】‘%(c,res)) return ‘失败‘ return ‘成功‘
4.write_excel()函数,写excel。获取返回每条用例的执行结果cases_res。需导入xlutils模块。
注:在get_case()函数里,定义了: self.file_path = file_path ,因此在该函数write_excel()中不需要再传入file_path参数,可以直接调用,否则需要在write_excel()函数中传入参数file_path。
首先需要了解用例返回结果样式:返回一个二维数组:[[‘abcxx,‘通过’],[abxx2,‘失败’]....],将结果写入返回报文和测试结果列。
from xlutils import copy def write_excel(self,cases_res): # [ [‘dsfd‘,"通过"] ,[‘sdfsdf‘,‘失败‘] ] book = xlrd.open_workbook(self.file_path) new_book = copy.copy(book) sheet = new_book.get_sheet(0) row = 1 #从第二行开始写,第一行是表头 for case_case in cases_res: #获取到每一个结果 sheet.write(row,8,case_case[0]) #写第8列 sheet.write(row,9,case_case[1]) #写第9列 row+=1 new_book.save(self.file_path.replace(‘xlsx‘,‘xls‘)) #如果是xlsx结尾的将替换为xls结尾,保证excel可以打开
二.在lib下写发邮件的类:send_mail.py
发邮件是需要定义一些变量、常量,因此将这些内容写在配置文件setting里便于管理。
import yagmail from conf import setting #将setting文件里定义的常量导入 from lib.log import atp_log #导入lib下的log文件,写日志 def sendmail(title,content,attrs=None): m = yagmail.SMTP(host=setting.MAIL_HOST,user=setting.MAIL_USER ,password=setting.MAIL_PASSWRD,smtp_ssl=True #当是qq邮箱时,需加入smtp_ssl=True ) m.send(to=setting.TO,subject=title, contents=content, attachments=attrs) atp_log.info(‘发送邮件完成‘)
三.在conf下新建setting.py,配置文件里定义各种需要的变量,常量,修改时,方便。
import os BASE_PATH = os.path.dirname( os.path.dirname(os.path.abspath(__file__)) #获取ATP所在的路径 ) MAIL_HOST=‘smtp.163.com‘ MAIL_USER=‘liu.****@163.com‘ MAIL_PASSWRD = ‘p888****g421‘ TO = [ ‘5472*****@qq.com‘, ] LEVEL = ‘debug‘ #日志级别 LOG_PATH = os.path.join(BASE_PATH,‘logs‘) #存放日志的路径,动态获取的,无论文件存放位置 CASE_PATH = os.path.join(BASE_PATH,‘cases‘) #存放日志的路径 LOG_NAME=‘atp.log‘ #日志的文件名
四.在lib下log.py文件。写日志文件,在其他文件抛异常时,会打印日志,直接调用该文件。
import logging,os from logging import handlers from conf import setting class MyLogger(): def __init__(self,file_name,level=‘info‘,backCount=5,when=‘D‘): logger = logging.getLogger() # 先实例化一个logger对象,先创建一个办公室 logger.setLevel(self.get_level(level)) # 设置日志的级别的人 cl = logging.StreamHandler() # 负责往控制台输出的人 bl = handlers.TimedRotatingFileHandler(filename=file_name, when=when, interval=1, backupCount=backCount, encoding=‘utf-8‘) fmt = logging.Formatter(‘%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s‘) cl.setFormatter(fmt) # 设置控制台输出的日志格式 bl.setFormatter(fmt) # 设置文件里面写入的日志格式 logger.addHandler(cl) logger.addHandler(bl) self.logger = logger def get_level(self,str): level = { ‘debug‘:logging.DEBUG, ‘info‘:logging.INFO, ‘warn‘:logging.WARNING, ‘error‘:logging.ERROR } str = str.lower() return level.get(str) path = os.path.join(setting.LOG_PATH,setting.LOG_NAME) #拼好日志的绝对路径 atp_log = MyLogger(path,setting.LEVEL).logger #日志级别 #直接在这里实例化,用的时候就不用再实例化了
五.在bin下新建start.py。start.py文件是启动文件,程序的入口,串联整个系统功能的所有逻辑。
import os,sys BASE_PATH = os.path.dirname( os.path.dirname(os.path.abspath(__file__)) #获取ATP的路径 ) sys.path.insert(0,BASE_PATH) #将ATP目录下的所有文件加到环境变量,这样保证以后在哪里运行都可以 from lib.common import OpCase #导入读取用例的类 from lib.send_mail import sendmail #导入发邮件的类 from conf import setting #导入配置文件 class CaseRun(object): #启动的类 def find_cases(self): op = OpCase() #实例化获取用例的类,便于调用OpCase()类下的函数 for f in os.listdir(setting.CASE_PATH):#每次循环的时候读一个excel abs_path = os.path.join(setting.CASE_PATH,f) #拼成绝对路径,f只是一个文件名 case_list = op.get_case(abs_path) #调用OpCase()类下的获取用例的函数,获取所有用例 res_list = [] pass_count,fail_count = 0,0 for case in case_list:#循环每个excel里面所有用例 url,method,req_data,check = case #check:预期结果 res = op.my_request(url,method,req_data) #调用完接口返回的结果,res:实际结果 status = op.check_res(res,check) #调用check_res()函数,校验预期结果&实际结果 res_list.append([res,status]) #将返回结果和测试结果加入一个list,定义res_list,便于写入excel if status==‘通过‘: pass_count+=1 else: fail_count+=1 op.write_excel(res_list) #将res_list(返回报文,测试结果)写入excel msg = ‘‘‘ xx你好: 本次共运行%s条用例,通过%s条,失败%s条。 ‘‘‘%(len(res_list),pass_count,fail_count) sendmail(‘测试用例运行结果‘,content=msg,attrs=abs_path) #发邮件
六.启动:在start.py文件中:
CaseRun().find_cases() #调用find_cases函数
欧了,整个简单的自动化框架包装完毕。
标签:调用 with 动态获取 一件事 位置 method 二维数组 环境变量 std
原文地址:https://www.cnblogs.com/fancyl/p/9105422.html