1.前言
项目接口较多,测试场景多,版本更新影响范围广,为了能及时对改动影响的所有模块遍历测试场景,故开发此新版接口自动化。为了易于维护,选择了python+unittest+excel模式,当前版本只需在excel测试文件中进行模块、用例的增删改,实现了脚本和用例完全脱离。
环境:Python、Unittest、BeautifulReport、Excel
- BeautifulReport模块做了自定义修改,生成的html报告中用例描述由原先的函数描述改为测试执行函数中的title变量,请直接将文件夹BeautifulReport粘贴至X:\Python36\Lib\site-packages文件夹下
2.文件结构介绍
common
base_assert.py:断言,目前仅支持assertEqual和assertIn,后续根据需要维护添加
read_ini.py:读取config.ini中的固定配置项如域名、token
log.py:日志,支持debug、info、warning、error、critical日志
read_excel.py:读取excel测试用例并初始化,包括用例中的关键字替换
base_run.py:单用例执行方法,setup函数、teardown函数、testcase函数
request_func.py:封装request方法,目前支持POST、GET,后续可根据需要维护添加
trans_json.py:封装处理字典json转换
config
config.ini:域名配置、token配置
file_path.py:所有需要传入的文件地址
log
log.log:所有日志信息
error.log:报错日志信息
report
xxxx.html:报告html
run.py:执行用例集
test_case_data.xlsx:测试用例
3.测试用例参数
test_case_data.xlsx
用例参数
|
枚举
|
解释说明 |
---|---|---|
case_id | testcase001 | 测试用例编号,同时也是测试类名 |
case_module | test_createApp | 测试用例接口模块,同时也是测试执行函数名称,必须以test开头 |
case_name | (开发者)新建应用:正常调用 | 测试用例描述 |
username | usernamex,/,空 | 用户名,需要切换账号时填入,如果使用上次登录的账号则使用"/",如果不需要登录直接为空 |
password | passwordx,/,空 | 密码,同用户名一致 |
method | POST,GET | 接口类型,暂时仅支持post、get |
url_path | /user2/xxx/xxx | 接口url地址 |
api_type | web,oauth | 接口网关类型,web接口则使用web网关的域名,如果是oauth则使用oauth域名 |
headers | {},空 | 接口请求头,如果需要指定则填上,如果不需要则传入{}空括号,如果是公共接口则为空 |
request_body | {“xx”:“xx_<time_stamp>”},空 | 有入参则输入,没有为空,目前支持<time_stamp>标志转换为当前时间戳(保留13位),对于新建的业务场景可以添加时间戳标志使用例可以重复执行 |
status_code | 200 | 预期状态码 |
resp_expect | “xx”:“xx” | 预期返回结果,只要包含返回结果的关键字部分即可 |
save_data | userUid | 返回参数中期望保存的字段存入字典,当前仅支持一级结构的key,如果希望保存二级结构的key需要另外处理,另外如果想保存多个参数也需要优化脚本 |
use_data | testcaseXXuserUid | 使用关联的标识,由用例编号+字段组成,当读取到标识存在时会把入参中的关键字替换为字典中暂存的值,目前只支持单参数处理,后续优化为多参数 |
注意:测试用例读取逻辑为一次性所有读取后批量处理需要替换的参数,如果多条用例都使用了<time_stamp>标识,会把所有标识替换成相同时间戳,所以编写测试用例时注意避免重复问题,例如创建多个应用可以使用"app1<time_stamp>",“app2<time_stamp>”,“app3<time_stamp>”
4.关键代码
read_ini.py
def read_inifile():
# 读取配置
try:
config = configparser.ConfigParser()
config.read(file_path.config_file)
except Exception as e:
MyLog.error('\033[31m {} \033[0m'.format(e))
raise
return config
class GetIni:
def __init__(self, inikey, inivalue, newvalue=None):
# 初始化配置
self.inikey = inikey
self.inivalue = inivalue
self.newvalue = newvalue
self.config = read_inifile()
def get_ini(self):
# 返回配置文件的某项参数值
try:
convalues = self.config.get(self.inikey, self.inivalue)
except Exception as e:
MyLog.error('\033[31m {} \033[0m'.format(e))
raise
return convalues
def write_ini(self):
# 修改配置文件的某项参数值
try:
self.config.set(self.inikey, self.inivalue, self.newvalue)
self.config.write(open(file_path.config_file, 'w'))
except Exception as e:
MyLog.error('\033[31m {} \033[0m'.format(e))
raise
read_excel.py
def read_xlrd(excel_file):
'''读取excel所有数据'''
try:
data=xlrd.open_workbook(excel_file)
# 获取所有sheet名
sheets=data.sheet_names()
datafile=[]
now=int(round(time.time() * 1000))
for sheet in sheets:
#遍历所有sheet的数据
table=data.sheet_by_name(sheet)
for rowNum in range(table.nrows