一、接口自动化测试的流程
1、需求分析
1、1请求(url,方法、数据)
2、挑选需要做自动化测试的接口
3、设计自动化测试用例
4、搭建自动化测试环境
5、设计自动化执行框架(报告、参数化、 用例执行框架)
6、编写代码
7、执行用例(unittest、pytest)
8、生成测试报告(htmltextrunner\allure)
【视频教程:阿里测开带你30天学完自动化测试从入门到入职极限压缩精品教程,碾压99%7天速成下水道教程_哔哩哔哩_bilibili
】
二、用例设计
2、1单接口
模板:id,模块,接口名称,请求url,用例名称,请求方法,请求参数类型,请求参数,预期结果,实际结果,备注
注意:单接口颗粒度放的比较小(以测试数据为颗粒度)
2、2多接口
模板:id,模块,接口名称,请求url,用例名称,请求方法,请求参数类型,请求参数,预期结果,实际结果,备注
注意:多个接口颗粒度为每个接口为基础,每个接口内所设计的数据可以通过参数化来解决。
三、自动化目录结构
1、配置层(common)
1 2 3 4 5 6 7 8 9 |
|
2、用例执行业务层(testcase)
import pytest,json,allure from util.apiutil import Request from util.yamlutil import OperationYaml from util.excelutil import OperationExcel,ExcelVarles obj = Request() objYaml = OperationYaml() objExcel = OperationExcel() data_key = ExcelVarles class TestExcel: # request封装 def run_api(self, url, method, params=None, headers=None, cookies=None): if str(method).lower() == "get": res = obj.get(url, params=params, headers=headers, cookies=cookies) elif str(method).lower() == "post": res = obj.post(url, json=params, headers=headers, cookies=cookies) return res # 运行前置用例 def run_pre(self, pre_case): url = objYaml.readbaseyaml()["test_url"] + pre_case[data_key.url] method = pre_case[data_key.method] params = eval(pre_case[data_key.params]) headers = pre_case[data_key.headers] header = self.json_parse(headers) cookies = pre_case[data_key.cookies] res = self.run_api(url, method, params, header) print("前置用例执行:%s" % res) return res @pytest.mark.parametrize('datas',objExcel.runs()) # 运行测试用例 def test_login(self,datas): url = objYaml.readbaseyaml()["test_url"] + datas[data_key.url] print(url) case_id = datas[data_key.case_id] case_model = datas[data_key.case_model] case_name = datas[data_key.case_name] pre_exec = datas[data_key.pre_exec] method = datas[data_key.method] params = eval(datas[data_key.params]) expect_result = datas[data_key.expect_result] headers = datas[data_key.headers] cookies = datas[data_key.cookies] code = datas[data_key.code] db_verify = datas[data_key.db_verify] if pre_exec: pass pre_case = objExcel.case_prev(pre_exec) print("前置条件信息为:%s" % pre_case) pre_res = self.run_pre(pre_case) headers = self.get_correlation(headers,pre_res) header = self.json_parse(headers) res = self.run_api(url, method, params, header, cookies) print("测试用例执行:%s" % res) assert expect_result in str(res["body"]["message"]) assert code == int(res["code"]) # 对allure报告进行配置 # allure # sheet名称 feature 一级标签 # allure.dynamic.feature(sheet_name) # 模块 story 二级标签 allure.dynamic.story(case_model) # 用例ID+接口名称 title allure.dynamic.title(case_id + case_name) # 请求URL 请求类型 期望结果 实际结果描述 desc = "<font color='red'>请求URL: </font> {}<Br/>" \ "<font color='red'>请求类型: </font>{}<Br/>" \ "<font color='red'>期望结果: </font>{}<Br/>" \ "<font color='red'>实际结果: </font>{}".format(url, method, expect_result, res) allure.dynamic.description(desc) def json_parse(self,data): # 格式化字符,转换json # if headers: # header = json.loads(headers) # else: # header = headers return json.loads(data) if data else data # token参数关联替换 def get_correlation(self,header,pre_res): # 验证是否有关联 headers_para = objExcel.params_find(header) if len(headers_para): # 有关联,执行前置用例,获取结果 headers_data = pre_res["body"]["data"]["token"][headers_para[0]] # 结果替换 headers = objExcel.res_sub(header, headers_data) return headers if __name__ == '__main__': pytest.main(["-s", "-v", "test_single_api.py"])
3、数据驱动(data)
存放excel,yaml文件
4、测试报告(report)
5、工具层(第三方工具包)
apiutil.py
import requests class Request(): def requests_api(self,url, json=None, headers=None, cookies=None, params=None, data=None,method="get"): if method == "get": r = requests.get(url=url,headers=headers,cookies=cookies,params=params,data=data) elif method == "post": r = requests.post(url=url,json=json,headers=headers,cookies=cookies) elif method == "put": r = requests.put(url=url,headers=headers,cookies=cookies,params=params) elif method == "delete": r =requests.delete(url=url,headers=headers,cookies=cookies,params=params) code = r.status_code try: body = r.json() except Exception as e: body = r.text res = dict() res["code"] = code res["body"] = body return res def get(self,url,**kwargs): return self.requests_api(url, method="get", **kwargs) def post(self,url,**kwargs): return self.requests_api(url, method="post", **kwargs) def put(self,url,**kwargs): return self.requests_api(url, method="put", **kwargs) def delete(self,url,**kwargs): return self.requests_api(url, method="delete", **kwargs)
excelutil.py
import xlrd from common.basepath import * import json import re p_data = '\${(.*)}\$' class ExcelVarles: case_id = "用例ID" case_model = "模块" case_name = "接口名称" url = "请求URL" pre_exec = "前置条件" method = "请求类型" params_type = "请求参数类型" params = "请求参数" expect_result = "预期结果" actual_result = "实际结果" beizhu = "备注" is_run = "是否运行" headers = "headers" cookies = "cookies" code = "status_code" db_verify = "数据库验证" class OperationExcel: @property def getExcelDatas(self): datas = list() book = xlrd.open_workbook(filePath('data', 'api.xlsx')) getsheet = book.sheet_by_index(0) title = getsheet.row_values(0) for row in range(1,getsheet.nrows): row_values=getsheet.row_values(row) datas.append(dict(zip(title,row_values))) return datas def runs(self): # 获取到可执行的测试用例 run_list=[] for item in self.getExcelDatas: isRun=item[ExcelVarles.is_run] if isRun == 'y': run_list.append(item) else: pass return run_list def params(self): '''对请求参数为空做处理''' params_list=[] for item in self.runs(): params=item[ExcelVarles.params] if len(str(params).strip())==0: pass elif len(str(params).strip())>=0: params=json.loads(params) def case_prev(self,casePrev): # 据前置测试条件找到关联的前置测试用例 for item in self.getExcelDatas: if casePrev in item.values(): return item return None def res_find(self,data, pattern_data=p_data): # 查询 # pattern = re.compile('\${(.*)}\$') pattern = re.compile(pattern_data) re_res = pattern.findall(data) return re_res def res_sub(self,data, replace, pattern_data=p_data): # 替换 pattern = re.compile(pattern_data) re_res = pattern.findall(data) if re_res: return re.sub(pattern_data, replace, data) return re_res def params_find(self,headers): # 验证请求中是否有${}$需要结果关联 if "${" in headers: headers = self.res_find(headers) return headers
yamlutil.py
import yaml from common.basepath import filePath class OperationYaml: def readYaml(self,fileDir='data',fileName='login.yaml'): ### 获取login测试用例 with open(filePath(fileDir=fileDir, fileName=fileName),'r',encoding='utf-8') as f: return list(yaml.safe_load_all(f)) def readbaseyaml(self,fileDir='data',fileName='base.yaml'): with open(filePath(fileDir=fileDir, fileName=fileName), 'r', encoding='utf-8') as f: return yaml.safe_load(f) def readgoodsyaml(self,fileDir='data',fileName='goods.yaml'): ### 获取商品测试用例 with open(filePath(fileDir=fileDir, fileName=fileName), 'r', encoding='utf-8') as f: return list(yaml.safe_load_all(f))
6、运行入口层(运行测试用例,并生成报告)