![]() |
||
---|---|---|
common | ||
config | ||
pic | ||
test_suite | ||
util | ||
.gitignore | ||
README.md | ||
conftest.py | ||
pytest.ini | ||
requirements.txt | ||
setupMain.py |
README.md
接口自动化测试框架 pytest+ymal+allure+requests
联系方式
QQ 529548204
邮箱 529548204@qq.com
如果有问题请联系我 大家共同学习共同进步~
前言
框架采用python的pytest模块, 搭配requests以及allure测试报告,可以发送钉钉通知邮件通知 可以根据yaml测试数据自动生成用例, 支持接口关联, 支持类似jmeter的函数助手, 可以通过脚本进行接口录制,辅助编写yaml测试数据文件, 支持数据库断言, 支持分布式,jenkins持续集成。
一、目录结构
|--接口自动化测试框架 # 主目录
├─ common # 封装断言以及requests的方法
├─ caches # 本地缓存保存路径
├─ config # 配置文件读取
└─ config.ini
├─ testsuite # 测试相关文件
├─ datas #测试数据
└─ 项目文件夹 名称同config中 testname一致 # 可以通过newproject脚本生成
└─ login.yml # 用例数据 格式参考下面YAML PARAM格式说明
├─ testcase
└─ 项目文件夹 名称同config中 testname一致 # 测试用例 可以通过writepage脚本生成
└─ test_login.py
└─recording # 录制脚本文件夹放录制的接口文档
├─ util # 常用工具 用例生成 接口录制
├─ tools # 内部调用工具方法包含yaml读取 函数助手 数据库链接等
└─ scripts # 包含生成新项目,自动生成用例,接口录制
├─ log # 日志
├─ report # allure测试报告
├─ pytest.ini # pytest配置
├─ requirements.txt
├─ README.md
└─ setupMain.py # 整体执行程序。
二、关键文件介绍
1.yaml测试数据格式
1.1 本地缓存介绍
保存本地缓存方法为3种
1. body 请求体内的参数中保存:
body如果是 "id=2&path=haha" 会转换成字典 然后根据path使用jsonpath取值
2. response : 从json格式的响应结果中获取
3. cookies: 保存响应结果的cooies到本地
读取本地缓存方法
将需要替换为缓存数据的内容改成:$caches(cookies)$
示例:
cache: # 本地缓存
- cachefrom: 'body'
path: '$.code'
name: 'code'
# 使用方法 需要的地方替换为$caches(code)$
- cachefrom: 'response'
path: '$.data'
name: 'data'
# 使用方法 需要的地方替换为$caches(data)$
- cachefrom: 'cookies'
path: # cookies 时path为空
name: 'cookies'
# 使用方法 需要的地方替换为$caches(cookies)$
1.2 接口关联介绍
通过relevance字段来判断是否需要关联 如果不需要relevance字段为空即可
示例:
下面示例为 关联接口为tradeAdd 与 tradeAdd2两条yaml数据中case的第一条和第二条
分别去这两个接口返回结果的 id 并命名为tradeId 、tradeId2
内存中会保存成字典格式
{"tradeId":"10","tradeId2":"11"}
读取方法:$relevance(tradeId2)$
relevance:
response:
- relCaseName: tradeAdd # 其他testcase的ID
relCaseNum: 1 # 关联的case数组里 第几条数据
value: $.id # 当前返回结果的jsonpath
name: tradeId # 关联值名称
- relCaseName: tradeAdd2 # 其他testcase的ID
relCaseNum: 2 # 关联的case数组里 第几条数据
value: $.id # 当前返回结果的jsonpath
name: tradeId2 # 关联值名称
1.3 参数介绍
file
: 通过case外关键字file判断是否需要上传文件 如果需要则格式为:{上传文件的参数名:文件路径}
param
:包含两种请求格式
(1)json格式 { "username": "finsiot","password": "$caches(pwd)$" # 读取缓存值 }
(2)param格式 username=admin&password=123
urlparam
:{ id: 123 }
路径参数 address中 v1/api/$url(id)$/
中会根据id替换为123
data:
file: {
files: D:\test\test.csv # 上传文件的参数名:文件路径
}
param: {
"username": "finsiot","password": "$caches(pwd)$" # 读取缓存值
}
urlparam: {
id: 123
}# 路径参数 v1/api/$url(id)$/
1.4 断言介绍
jsonpath
json格式数据断言:
根据json路径格式来获取实际结果同value中的预期结果进行判断
sqlassert
数据库结果断言
可同时判断多个结果值
根据sql中的查询语句查询出来的 第一条结果进行判断
time
响应时间断言 默认为2秒
code
http响应码断言
assert:
jsonpath:
- {
"path": "$.data.expense_trend[0].peak_hour.peak_hour",
"value": "123", # 预期结果
"asserttype": "==" # 判断相等
}
- {
"path": "$.code",
"value": 0,
"asserttype": "=="
}
- {
"path": "$.data.id",
"value": 196,
"asserttype": "=="
}
sqlassert:
# 如果不需要 此字段置空即可
- {
"datas": [
{
"path": "$.data.id",
"name": "id"
},
{
"path": "$.data.username",
"name": "username"
},
],
"sql": "select * from saas.user where username = '****'",
# 取数据库查询出的第一条数据进行验证 如果存在 列名 username 值为$.data.username则通过
"db_name": "database" # 判断链接那个数据库
}
time: 2 # 响应时间断言
code: 200
1.4 生成随机数据介绍
部分数据采用faker库生成
int_num = "$RandomPosInt(1,333)$" # 267
str_num = '$RandomString($RandomPosInt(2,23)$)$$RandomPosInt(1,333)$' # AbE3c14580f29aDFe5
float_num = '$RandomFloat($RandomPosInt(2,13)$,$RandomPosInt(2,13)$,$RandomPosInt(2,13)$)$' # 11.84864
time_num = '$GetTime(time_type=else,layout=%Y-%m-%d %H:%M:%S,unit=0,0,0,0,0)$' # 当前时间 2022-04-14 13:27:01
time_num2 = '$GetTime(time_type=future,layout=%Y-%m-%d %H:%M:%S,unit=0,0,0,3,0)$' # 未来时间3天后 2022-04-17 13:32:42
time_num3 = '$GetTime(time_type=past,layout=%Y-%m-%d %H:%M:%S,unit=0,0,0,3,0)$' # 过去时间3天前 2022-04-11 13:33:24
choice_num = '$Choice($RandomPosInt(2,13)$)$' # 6
email = "$faker(email)$"# 邮箱 # xkong@example.net
idcard = "$faker(idcard)$" # 130802196003197594
province = "$faker(province)$" # 新疆维吾尔自治区
city = "$faker(city)$" # 鹏市
phone_number = "$faker(phone_number)$" # 15070673645
name = "$faker(name)$" # 许云
1.4 后置请求处理
使用场景: 新增数据A之后一系列用例执行完需要后置来还原数据形成业务闭环.
datatype 有3种类型 param json 和urlparam
dataname为后置关联的参数中参数名称
path为当前请求返回结果的jsonpath 根据path的值更换后置处理参数值
如果不需要后置处理 teardown 置空即可
teardown:
- tdName: pointDel # 其他testcase的ID
tdNum: 1 # 关联的case数组里 第几条数据
tddata:
- datatype: param
dataname: name
path: $.name
- datatype: urlparam
dataname: pointId
path: $.id
- tdName: pointAdd # 其他testcase的ID
tdNum: 1 # 关联的case数组里 第几条数据
tddata:
- datatype: json
dataname: name
path: $.name
- datatype: urlparam
dataname: pointId
path: $.id
三、文件展示
###3.1yaml文件展示
!!!所有case的id 务必唯一!!!
name: "登录"
# 测试用例模块名称
token: Authorization
# 判断此接口是否使用token false 或者"cookie"或者"Authorization"等 如果不需要 置空或者填写false
order: 1
用例执行顺序 @pytest.mark.run(order=1) # 因为此功能不支持分布式录制中已取消file
: bool值判断 true为此接口需要上传文件参数
case
: 测试用例数据
login: # caseID **请务必唯一**
name: "登录" #测试用例模块
token: false # 判断此接口是否使用token false 或者"cookie"或者"Authorization"等
# token: "Authorization"
order: 1 # 用例执行顺序 @pytest.mark.run(order=1) 因为此功能不支持分布式录制中已取消
file: true # bool值 true为需要文件的接口
case:
- info: "用户名登录-成功" # 用例信息
host: 'host' # config.ini里面 请求host的key
address: '/v1/apps/$url(region_id)$/' # $url(region_id)$ 正则匹配参数中的路径参数
method: 'post'
cache: # 本地缓存
# 保存本地缓存方法为3种
# 1. body 请求体内的参数中保存:
# body如果是 "id=2&path=haha" 会转换成字典 然后根据path使用jsonpath取值
# 2. response : 从json格式的响应结果中获取
# 3. cookies: 保存响应结果的cooies到本地
- cachefrom: 'body'
path: '$.code'
name: 'code'
# 使用方法 需要的地方替换为$caches(code)$
- cachefrom: 'response'
path: '$.data'
name: 'data'
# 使用方法 需要的地方替换为$caches(data)$
- cachefrom: 'cookies'
path: # cookies 时path为空
name: 'cookies'
# 使用方法 需要的地方替换为$caches(cookies)$
# 接口关联
relevance:
# 判断如果不需要关联relevance字段为空即可
# 如果需要关联就
response:
# 场景 接口A删除请求,需要接口B新增请求中返回的ID以及name
- relCaseName: pointAdd # 其他testcase的ID
relCaseNum: 1 # 关联的case数组里 第几条数据
reldata:
- value: $.id # 当前返回结果的jsonpath
name: pointId # 关联值名称
- value: $.name # 当前返回结果的jsonpath
name: pointname # 关联值名称
teardown:
- tdName: pointDel # 后置请求的caseID
tdNum: 1 # 后置请求的case数组里 第几条数据
tddata:
- datatype: param
dataname: name
path: $.name
- datatype: urlparam
dataname: pointId
path: $.id
- datatype: json
dataname: name
path: $.name
# 机制为 根据relevance字段生成字典{"tradeId":"123"}
# 使用关联值方法为将需要替换的地方修改为 $relevance(tradeId)$
headers: {
"Content-Type": "application/json"
}
data:
file: {
files: D:\test\test.csv # 上传文件的参数名:文件路径
}
param: {
"username": "finsiot","password": "$caches(pwd)$" # 读取缓存值
}
urlparam: {
id: 123
}# 路径参数 v1/api/$url(id)$/
assert:
jsonpath:
- {
"path": "$.data.expense_trend[0].peak_hour.peak_hour",
"value": "123",
"asserttype": "=="
}
- {
"path": "$.code",
"value": 0,
"asserttype": "=="
}
- {
"path": "$.data.id",
"value": 196,
"asserttype": "=="
}
sqlassert:
# 如果不需要 此字段置空即可
- {
"datas": [
{
"path": "$.data.id",
"name": "id"
},
{
"path": "$.data.username",
"name": "username"
},
],
"sql": "select * from saas.user where username = '****'",
# 取数据库查询出的第一条数据进行验证 如果存在 列名 username 值为$.data.username则通过
"db_name": "database" # 判断链接那个数据库
}
time: 2 # 响应时间断言
code: 200 # HTTP响应码断言
2.config.ini配置文件格式
重点为[directory] 中的test_name 所有程序都围绕test_name 进行执行 根据testname来生成测试用例执行测试等
[directory] # 路径相关
log_dir = /logs
data_dir = /datas
page_dir = /page
report_xml_dir = /report/xml
report_html_dir = /report/html
test_suite = /test_suite
case_dir = /testcase
cache_dir = /caches
test_name = 测试项目名称: saasWeb
[host]
http_type = http
host =
[email]
;服务器
mail_host = smtp.sina.com
;发送邮箱
mail_user =
;口令
mail_pass =
;发送者
sender =
;接收邮箱
receivers =
[database]
host = 192.
port = 3306
user = root
password =
;database =
database =
charset = utf8
[dingding]
webhook =
secret =
四、操作方法
- 新建config/config.ini文件 格式如上例子
- 执行util/scripts/newProject.py 根据testname生成测试项目基础目录
- 在生成的test_suite/datas/testname 文件夹下增加yaml测试用例
- 执行util/scripts/writeCase.py生成测试脚本 关于token 需要根据自己项目情况修改yaml文件中token关键字 如果不需要token值为false 需要token则改为需要的类型
- 执行setupMain.py开始测试
五、代码展示
test_login.py
login.yml
conftest.py
总结
这里给大家分享出来希望能和朋友们共同学习,共同进步 源码地址 https://gitee.com/a529548204/apitest