每天进步一点点,关注我们哦,每天分享测试技术文章
码同学抖音 :小码哥聊软件测试
1.数据驱动框架设计
1.框架结构
2.excel数据规则设计
按照一定的维度进行分类,每个分类可以当做一个sheet工作表
变量名称 |
变量值 |
host |
http://82.xxx74.xx:xxxx |
username |
18866668888 |
password |
123456 |
表单类型时:
{ "data":{ "xxx":"xxjsdhdh" }}
查询参数:
{ "params":{ "xxx":"xxjsdhdh" }}
json参数:
{ “json”:{ “xxx”:”xxjsdhdh” }}
混合参数,比如既有表单又有查询:
{ "params":{ "xxx":"xxjsdhdh" }, "data":{ "ddd":"ddff" }}
接口名称 |
默认参数 |
登录 |
{ “data”:{ “username”:”${username}”, “password”:”${password}” } } |
新增客户 |
{ “json”:{ “entity”: { “customer_name”: “沙陌001”, “mobile”: “18729399607”, “telephone”: “01028375678”, “website”: “http://mtongxue.com/”, “next_time”: “2022-05-12 :00”, “remark”: “这是备注”, “address”: “北京市,北京城区,昌平区”, “detailAddress”: “霍营地铁口”, “location”: “”, “lng”: “”, “lat”: “” } } } |
新建联系人 |
{ “json”:{ “entity”: { “name”: “沙陌001联系人”, “customer_id”:”${customerId}”, “mobile”: “18729399607”, “telephone”: “01028378782”, “email”: “sdsdd@qq.com”, “post”: “采购部员工”, “address”: “这是地址”, “next_time”: “2022-05-10 :00”, “remark”: “这是备注” } } } |
新建产品 |
{ “json”:{ “entity”: { “name”: “python全栈自动化”, “category_id”: 23, “num”: “98888”, “price”: “6980”, “description”: “接口/web/app/持续集成” } } } |
2.数据驱动框架底层代码实现
1.创建项目
依赖于设计去创建项目结构
2.excel数据读取
在common这个package下创建一个python文件,叫做testcase_util.py
# !/usr/bin python3 # encoding: utf-8 -*- # @file : testcase_util.py # @author : 沙陌 Matongxue_2# @Time : 2022-05-10 11:27# @Copyright: 北京码同学import openpyxl# 读取全局变量sheet工作表def get_variables(wb): sheet_data = wb['全局变量'] variables = {} # 用来存储读到的变量,名称是key,值是value lines_count = sheet_data.max_row # 获取总行数 for l in range(2,lines_count+1): key = sheet_data.cell(l,1).value value = sheet_data.cell(l,2).value variables[key] = value return variablesdef get_api_default_params(wb): sheet_data = wb['接口默认参数'] api_default_params = {} # 用来存储读到的变量,名称是key,值是value lines_count = sheet_data.max_row # 获取总行数 for l in range(2,lines_count+1): key = sheet_data.cell(l,1).value value = sheet_data.cell(l,2).value api_default_params[key] = value return api_default_params# 获取要执行的测试集合名称def get_casesuitename(wb): sheet_data = wb['测试集合管理'] lines_count = sheet_data.max_row # 获取总行数 cases_suite_name = [] # 用来存储要执行的测试集合名称 for l in range(2,lines_count+1): flag = sheet_data.cell(l,2).value if flag == 'y': suite_name = sheet_data.cell(l,1).value cases_suite_name.append(suite_name) return cases_suite_name# 需要根据要执行的测试集合名称来读取对应的测试用例数据def read_testcases(wb,suite_name): sheet_data = wb[suite_name] lines_count = sheet_data.max_row # 获取总行数 cols_count = sheet_data.max_column # 获取总列数 """ 规定读出来的测试数据存储结构如下: { “新增客户正确”:[ ['apiname','接口地址','请求方式','头信息',....], ['apiname','接口地址','请求方式','头信息',....], ], "新增客户失败-用户名为空":[ ['apiname','接口地址','请求方式','头信息',....] ], "新增客户失败-手机 格式不正确":[ ['apiname','接口地址','请求方式','头信息',....] ] } """ cases_info = {} #用来存储当前测试集合中的所有用例信息的 for l in range(2,lines_count+1): case_name = sheet_data.cell(l,2).value # 测试用例名称 lines = [] # 用来存储当前行测试数据的 for c in range(3,cols_count+1): cell = sheet_data.cell(l,c).value # 当前单元格数据 if cell == None: # 处理空单元格 cell = '' lines.append(cell) # 判断当前用例名称是否已存在于cases_info中 # 如果不存在,那就是直接赋值 # 否则就是在原来的基础上追加 if case_name not in cases_info: cases_info[case_name] = [lines] else: cases_info[case_name].append(lines) return cases_info# 整合所有要执行的测试用例数据,将其转成pytest参数化需要的数据结构格式def get_all_testcases(wb): """ 整合后的数据结构是 [ ['新增客户接口测试集合','新增客户正确',[[],[]]], ['新增客户接口测试集合','新增客户失败-用户名为空',[[],[]]], ['新增客户接口测试集合','新增客户失败-手机 格式不正确',[[],[]]], ['新建产品接口测试集合','新建产品正确',[[],[]]], ['新建产品接口测试集合','新建产品失败-产品编码重复',[[],[]]], ] :param wb: :return: """ test_data = [] # 用来存储所有测试数据 # 获取所有要执行的测试集合名称 cases_suite_name = get_casesuitename(wb) for suite_name in cases_suite_name: # 遍历读取每个要执行的测试集合sheet工作表中的测试用例数据 cur_cases_info = read_testcases(wb,suite_name) # 是个字典 for key,value in cur_cases_info.items(): # key实际上就是测试用例名称,value实际上测试用例多行数据信息 case_info = [suite_name,key,value] test_data.append(case_info) return test_dataif __name__ == '__main__': wb = openpyxl.load_workbook('../testcases/CRM系统接口测试用例.xlsx') # print(get_variables(wb)) # print(get_api_default_params(wb)) # print(get_casesuitename(wb)) # print(read_testcases(wb,'新增客户接口测试集合')) print(get_all_testcases(wb))
3.接口调用底层方法封装
在common目录下创建一个client.py,写上如下代码
# !/usr/bin python3 # encoding: utf-8 -*- # @file : client.py # @author : 沙陌 Matongxue_2# @Time : 2022-05-11 10:01# @Copyright: 北京码同学import jsonpathimport requestssession = requests.session()class RequestsClient: def send(self,url,method,**kwargs): try: self.resp = session.request(url=url,method=method,**kwargs) except BaseException as e: raise BaseException(f'接口发起异常:{e}') return self.resp # 针对jsonpath的数据提取封装一个方法 # 第一个参数指的是你要匹配的数据的jsonpath表达式 # 第二个指的是你想返回匹配到的第几个,默认是0返回第一个 def extract_resp(self,json_path,index=0): # 注意有的接口是没有返回信息的,返回信息是空的 text = self.resp.text # 获取返回信息的字符串形式 if text != '': resp_json = self.resp.json() # 获取响应信息的json格式 # 如果能匹配到值,那么res就是个列表 # 如果匹配不到res就是个False res = jsonpath.jsonpath(resp_json,json_path) if res: if index < 0: # 如果index小于0 ,我认为你要匹配到的所有结果 return res else: return res[index] else: print('没有匹配到任何东西') else: raise BaseException('接口返回信息为空,无法提取')if __name__ == '__main__': client = RequestsClient() client.send(url= 'http://82.156.74.26:9099/login', method='post', data={'username':'18866668888','password':'123456'}) print(client.extract_resp('Admin-Token'))
4.辅助函数封装及引用定义
在我们测试时,有的参数并不能够写死,所以这个时候我们希望某个参数在每次执行时都是动态变化的,那么就需要我们封装一些辅助随机函数来帮我们完成数据的动态变化
在common目录下建一个util_func.py的文件,在其中写上我们需要用到的辅助函数
随机数生成我们可以用一个第三方库faker
# !/usr/bin python3 # encoding: utf-8 -*- # @file : run.py # @author : 沙陌 Matongxue_2# @Time : 2022-05-10 11:24# @Copyright: 北京码同学import hashlibimport timefrom faker import Fakerfake = Faker(locale='zh_CN')def rdm_phone_number(): return fake.phone_number()def cur_timestamp():#到毫秒级的时间戳 return int(time.time() * 1000)def cur_date():# 2021-12-25 return fake.date_between_dates()def cur_date_time():# 2021-12-25 10:07:33 return fake.date_time_between_dates()def rdm_date(pattern='%Y-%m-%d'): return fake.date(pattern=pattern)def rdm_date_time(): return fake.date_time()def rdm_future_date_time(end_date): return fake.future_datetime(end_date=end_date)def md5(data): data = str(data) return hashlib.md5(data.encode('UTF-8')).hexdigest()if __name__ == '__main__': print(rdm_phone_number()) print(rdm_date()) print(rdm_date_time()) print(cur_date()) print(cur_timestamp()) print(cur_date_time()) print(rdm_future_date_time('+60d')) print(md5('123456'))
在excel中需要用到动态函数时,调用规则是${{md5(123456)}} 再比如${{rdm_future_date_time(+60d)}}
免费领取 码同学软件测试 课程笔记+超多学习资料+完整视频+最新面试题,可以转发文章 + 私信「码同学666」获取资料哦
5.excel中动态数据的正则替换
6.统一测试方法封装
针对框架去封装一个执行测试的入口,这个入口是一个基于pytest参数化的测试用例,在run.py中实现
在testcases_util.py中增加如下方法:
def update_value_to_json(json_object,json_path,new_value): json_path_expr = parse(json_path) for match in json_path_expr.find(json_object): path = match.path # 这是获取到匹配结果的路径 if isinstance(path,Index): match.context.value[match.path.index] = new_value elif isinstance(path,Fields): match.context.value[match.path.fields[0]] = new_value return json_object
在testcases_util.py中修改下述方法
def get_variables(wb): sheet_data = wb['全局变量'] variables = {} # 用来存储读到的变量,名称是key,值是value lines_count = sheet_data.max_row # 获取总行数 for l in range(2,lines_count+1): key = sheet_data.cell(l,1).value value = sheet_data.cell(l,2).value variables[key] = value # 增加一个内置变量,叫时间戳,注意这个时间戳是当前测试一运行就会产生,产生之后在当前测试未完成之前不管调用 # 多少次,都是一致的 variables['timestamp'] = cur_timestamp() return variables
# !/usr/bin python3
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!