新增用例:删除项目,修改用户手机号,修改用户密码,修改用户邮箱

This commit is contained in:
floraachy
2023-12-13 17:44:13 +08:00
parent 3c713a1ed3
commit 9db52bf23b
19 changed files with 519 additions and 63 deletions

2
.gitignore vendored
View File

@@ -9,3 +9,5 @@ __pycache__
outputs
Pipfile.lock
test_case/test_auto_case
test_scenario
config/settings_local.py

View File

@@ -15,12 +15,12 @@
* git地址: [https://www.gitlink.org.cn/floraachy/apiautotest](https://www.gitlink.org.cn/floraachy/apiautotest)
* 项目参与者: floraachy
* 技术支持邮箱: 1622042529@qq.com
* 个人主页: [https://www.gitlink.org.cn/floraachy](https://www.gitlink.org.cn/floraachy)
* 测试社区地址: [https://www.gitlink.org.cn/zone/tester](https://www.gitlink.org.cn/zone/tester)
* 入群二维码:[https://www.gitlink.org.cn/floraachy/apiautotest/issues/1](https://www.gitlink.org.cn/floraachy/apiautotest/issues/1)
对于框架任何问题,欢迎联系我
如果对您有帮助,请点亮 小星星 以表支持,谢谢
对于框架有任何问题,请先仔细阅读本文~ 如果还有不了解的,欢迎联系我!
## 二、实现功能
@@ -208,8 +208,8 @@ case_info: 具体的用例数据,是以列表的形式进行管理
message: 断言信息,非必填,可为空
expect_value: 预期结果
assert_type: 断言类型,支持如下:==, lt, le, gt, ge, not_eq, str_eq, len_eq, len_gt, len_ge, len_lt, len_le, contains, contained_by, startswith, endswith
type_jsonpath: 通过jsonpath表达式通响应数据提取实际结果与type_re任选其一
type_re: 通过正则表达式通响应数据提取实际结果与type_jsonpath任选其一
type_jsonpath: 通过jsonpath表达式从response.json()提取实际结果与type_re任选其一
type_re: 通过正则表达式从response.text提取实际结果与type_jsonpath任选其一;如果不填则默认获取response.text作为实际结果
```
注意:在进行断言的时候,左侧是预期结果,右侧是实际结果。比如我断言类型是`lt` 那么就是预期结果<实际结果
@@ -232,8 +232,41 @@ case_info: 具体的用例数据,是以列表的形式进行管理
type_jsonpath: $.user_id
```
### 7. 响应断言说明
todo 待补充ing
### 7. 数据库断言说明
数据库断言的参数说明:
```
断言标识(自定义,不为空即可,没有实际的意义):
message: 断言信息,非必填,可为空
sql: 数据库查询语句,必填
expect_value: 预期结果
assert_type: 断言类型,支持如下:==, lt, le, gt, ge, not_eq, str_eq, len_eq, len_gt, len_ge, len_lt, len_le, contains, contained_by, startswith, endswith
type_jsonpath: 通过jsonpath表达式通从数据库查询结果提取实际结果与type_re任选其一
type_re: 通过正则表达式从数据库查询结果提取实际结果与type_jsonpath任选其一;如果不填则默认SQL直接查询结果作为实际结果
```
注意:在进行断言的时候,左侧是预期结果,右侧是实际结果。比如我断言类型是`lt` 那么就是预期结果<实际结果
参考示例:
```
contains_user:
message: 断言数据库查询tokens表表中存在该登录用户记录预期查询结果的长度为1
sql: select * from tokens where user_id=${user_id};
expect_value: 1
assert_type: len_eq
contains_user2:
message: 断言数据库查询tokens表表中存在该登录用户记录;预期 ${user_id} in 查询结果jsonpath式匹配后的结果
sql: select * from tokens where user_id=${user_id};
type_jsonpath: $..user_id
expect_value: ${user_id}
assert_type: ==
contains_user3:
message: 断言数据库查询tokens表表中存在该登录用户记录预期 ${user_id} in 查询结果(正则表达式匹配后的结果)
sql: select * from tokens;
type_re: "'user_id': (.*?),"
expect_value: ${user_id}
assert_type: contains
```
### 8. Excel用例单独说明
框架支持excel多表单自动生成测试用例每一个表单作为一个测试用例模块。

View File

@@ -20,6 +20,9 @@ CONF_DIR = os.path.join(BASE_DIR, "config")
# 测试数据模块目录
DATA_DIR = os.path.join(BASE_DIR, "interface")
# gitlink测试数据模块目录
GITLINK_DIR = os.path.join(DATA_DIR, "gitlink")
# 测试文件模块目录
FILES_DIR = os.path.join(BASE_DIR, "files")

View File

@@ -18,14 +18,15 @@ ENV_VARS = {
"test": {
# 示例测试环境及示例测试账号
"host": "https://testforgeplus.trustie.net",
"client_id": "****client_id-test****", # 获取oauth_token需要的参数
"client_secret": "****client_secret-test****", # 获取oauth_token需要的参数
"green_code": "****green_code-test****", # 万能验证码
"login": "autotest",
"password": "****autotest-test****", # 运行时需要手动更改密码
"nickname": "autotest",
"user_id": 106,
"super_login": "floraachy",
"super_password": "****floraachy-test****",
"project_id": 59,
"repo_id": 59,
"super_password": "****floraachy-test****", # 运行时需要手动更改密码
"project_url": "/autotest/auotest",
"db_info": {
"db_host": "xx.xx.xx.xx",
@@ -41,17 +42,46 @@ ENV_VARS = {
}
},
"pre": {
# 示例测试环境及示例测试账号
"host": "http://172.20.32.202:4000",
"client_id": "****client_id-pre****", # 获取oauth_token需要的参数
"client_secret": "****client_secret-pre****", # 获取oauth_token需要的参数
"green_code": "****green_code-pre****", # 万能验证码
"login": "autotest",
"password": "****autotest-pre****", # 运行时需要手动更改密码
"nickname": "autotest",
"user_id": 115,
"super_login": "floraachy",
"super_password": "****floraachy-pre****", # 运行时需要手动更改密码
"project_url": "/floraachy/autotest",
"db_info": {
"db_host": "xx.xx.xx.xx",
"db_port": 3306,
"db_user": "root",
"db_pwd": "**********",
"db_database": "test**********",
"ssh": False,
"ssh_host": "xx.xx.xx.xx",
"ssh_port": 3306,
"ssh_user": "root",
"ssh_pwd": "**********"
}
},
"live": {
"host": "https://www.gitlink.org.cn",
"client_id": "****client_id-live****", # 获取oauth_token需要的参数
"client_secret": "****client_secret-live****", # 获取oauth_token需要的参数
"green_code": "****green_code-live****", # 万能验证码
"login": "floraachy",
"password": "****floraachy-live****",
"password": "****floraachy-live****", # 运行时需要手动更改密码
"nickname": "🌼陈银花",
"user_id": 87611,
"super_login": "chenyh",
"super_password": "****chenyh-live****",
"project_id": 1445676,
"repo_id": 1447291,
"super_password": "****chenyh-live****", # 运行时需要手动更改密码
"project_url": "/floraachy/auotest",
"db_info": {
"db_host": "xx.xx.xx.xx",

View File

@@ -23,10 +23,10 @@ case_info:
pageSize: 10000
round: 2
files:
extract:
assert_response:
status_code: 200
assert_sql:
extract:
-
id: case_glcc_demo_02
@@ -43,7 +43,7 @@ case_info:
pageSize: 20
round: 2
files:
extract:
assert_response:
status_code: 200
assert_sql:
assert_sql:
extract:

View File

@@ -0,0 +1,70 @@
# 公共参数
case_common:
allure_epic: GitLink接口
allure_feature: 登录模块
allure_story: 登录接口
case_markers:
- gitlink
- login: 登录接口
# 用例数据
case_info:
-
id: gitlink_login_oauth_token_01
title: 用户登录(密码模式)
run: True
severity: normal
url: /oauth/token
method: POST
headers:
Content-Type: application/json; charset=utf-8;
cookies:
request_type: json
payload:
grant_type: password
username: ${login}
password: ${password}
client_id: ${client_id}
client_secret: ${client_secret}
files:
assert_response:
status_code: 200
access_token_in_response:
message: 断言接口返回中存在access_token字段
expect_value: access_token
assert_type: contains
assert_sql:
extract:
type_jsonpath:
access_token: $.access_token
token_type: $.token_type
token_expires_in: $.expires_in
-
id: gitlink_login_oauth_token_02
title: 用户登录(客户端模式)
run: True
severity: normal
url: /oauth/token
method: POST
headers:
Content-Type: application/json; charset=utf-8;
cookies:
request_type: json
payload:
grant_type: client_credentials
client_id: ${client_id}
client_secret: ${client_secret}
files:
assert_response:
status_code: 200
access_token_in_response:
message: 断言接口返回中存在access_token字段
expect_value: access_token
assert_type: contains
assert_sql:
extract:
type_jsonpath:
access_token: $.access_token
token_type: $.token_type
token_expires_in: $.expires_in

View File

@@ -0,0 +1,44 @@
# 公共参数
case_common:
allure_epic: GitLink接口
allure_feature: 开源项目模块
allure_story: 组织
case_markers:
- gitlink
- projects
- gitea
- new_organization
- usefixtures: get_oauth_token
- skip: 参数image还没处理好暂时略过
# 用例数据
case_info:
-
id: gitlink_projects_new_organization_01
title: 新建组织
severity: critical
run: True
url: /api/organizations.json
method: POST
headers:
Content-Type: application/json; charset=utf-8;
Authorization: ${token_type} ${access_token}
cookies:
request_type: json
payload:
name: ${generate_identifier()} # 组织标识
nickname: ${generate_words()} # 组织名称
description: ${generate_paragraph()} # 组织描述
location: ${generate_city(full=False)} # 组织地区
repo_admin_change_team_access: true # 项目管理员可以添加或移除团队的访问权限
image: ${} # 组织图片
visibility: common # 组织可见性默认值common
files:
assert_response:
status_code: 200
assert_id_in_response:
message: 断言响应数据中存在id字段
assert_type: contains
expect_value: id
assert_sql:
extract:

View File

@@ -0,0 +1,40 @@
case_common:
allure_epic: GitLink接口
allure_feature: 开源项目模块
allure_story: 项目
case_markers:
- gitlink
- projects
- gitea
- delete_project
- usefixtures: new_project
case_info:
-
id: gitlink_projects_delete_project_01
title: 删除项目
severity: critical
run: True
url: /api/${repo_owner}/${repo_identifier}.json
method: DELETE
headers:
Content-Type: application/json; charset=utf-8;
Authorization: ${token_type} ${access_token}
cookies:
request_type: json
payload:
files:
extract:
assert_response:
status_code: 200
assert_status:
message: 断言接口status=0
expect_value: 0
assert_type: ==
type_jsonpath: $.status
assert_message:
message: 断言接口message=success
expect_value: success
assert_type: ==
type_jsonpath: $.message
assert_sql:

View File

@@ -22,7 +22,7 @@ case_info:
request_type: params
payload:
files:
extract:
assert_response:
status_code: 200
assert_sql:
assert_sql:
extract:

View File

@@ -5,8 +5,11 @@ case_common:
allure_story: 项目 # 故事可以理解为场景相当于method级的标签, 往下是 title
case_markers:
- gitlink
- projects
- gitea
- new_project
- usefixtures: gitlink_login
- usefixtures: get_oauth_token
- usefixtures: delete_project
# 用例数据
case_info:
@@ -19,7 +22,7 @@ case_info:
method: POST
headers:
Content-Type: application/json; charset=utf-8;
cookies: ${cookies}
Authorization: ${token_type} ${access_token}
cookies:
request_type: json
payload:
@@ -27,11 +30,6 @@ case_info:
name: ${generate_name(lan='zh')}_${generate_identifier()}
repository_name: ${generate_identifier()}
files:
extract:
type_jsonpath:
project_id: $.id
project_name: $.name
project_identifier: $.identifier
assert_response:
status_code: 200
login:
@@ -40,6 +38,12 @@ case_info:
assert_type: ==
type_jsonpath: $.login
assert_sql:
extract:
type_jsonpath:
repo_id: $.id
repo_name: $.name
repo_owner: $.login
repo_identifier: $.identifier
-
id: gitlink_projects_new_project_02
@@ -74,11 +78,6 @@ case_info:
blockchain_init_token:
auth_password:
files:
extract:
type_jsonpath:
project_id: $.id
project_name: $.name
project_identifier: $.identifier
assert_response:
status_code: 200
login:
@@ -87,6 +86,12 @@ case_info:
assert_type: ==
type_jsonpath: $.login
assert_sql:
extract:
type_jsonpath:
repo_id: $.id
repo_name: $.name
repo_owner: $.login
repo_identifier: $.identifier
-
id: gitlink_projects_new_project_03
@@ -104,11 +109,6 @@ case_info:
name: ${generate_name(lan='zh')}_${generate_identifier()}
repository_name: ${generate_identifier()}
files:
extract:
type_re:
project_id: $.id
project_name: $.name
project_identifier: $.identifier
assert_response:
status_code: 200
login:
@@ -121,4 +121,10 @@ case_info:
sql: select id,`name`, identifier from projects where user_id=${user_id} ORDER BY created_on DESC;
$.id: ${project_id}
$.name: ${project_name}
$.identifier: ${project_identifier}
$.identifier: ${project_identifier}
extract:
type_jsonpath:
repo_id: $.id
repo_name: $.name
repo_owner: $.login
repo_identifier: $.identifier

View File

@@ -23,9 +23,9 @@ case_info:
request_type: file
payload:
files: TOC出库订单导入模板(2).xlsx
extract:
type_jsonpath:
file_id: $.id
assert_response:
status_code: 200
assert_sql:
extract:
type_jsonpath:
file_id: $.id

View File

@@ -25,13 +25,6 @@ case_info:
password: ${password}
autologin: 1
files:
extract:
type_re:
nickname: \"username":"(.*?)"
login: \"login":"(.*?)"
user_id: \"user_id":(.*?),
type_response:
cookies: response.cookies
assert_response:
status_code: 200
user_id:
@@ -45,6 +38,13 @@ case_info:
assert_type: ==
type_jsonpath: $.login
assert_sql:
extract:
type_re:
nickname: \"username":"(.*?)"
login: \"login":"(.*?)"
user_id: \"user_id":(.*?),
type_response:
cookies: response.cookies
-
id: case_login_02
@@ -62,11 +62,6 @@ case_info:
password: ${password}
autologin: 1
files:
extract:
type_jsonpath:
nickname: $.username
login: $.login
user_id: $.user_id
assert_response:
status_code: 200
user_id:
@@ -96,6 +91,11 @@ case_info:
type_re: "'user_id': (.*?),"
expect_value: ${user_id}
assert_type: contains
extract:
type_jsonpath:
nickname: $.username
login: $.login
user_id: $.user_id
-
id: case_login_03
@@ -113,7 +113,6 @@ case_info:
password: 12345678900
autologin: 1
files:
extract:
assert_response:
status_code: 200
user_id:
@@ -122,3 +121,4 @@ case_info:
assert_type: ==
type_jsonpath: $.status
assert_sql:
extract:

View File

@@ -0,0 +1,45 @@
# 公共参数
case_common:
allure_epic: GitLink接口
allure_feature: 用户
allure_story: 账号管理
case_markers:
- gitlink
- gitea
- change_email
- login: 登录接口
- usefixtures: get_oauth_token
# 用例数据
case_info:
-
id: gitlink_user_change_email_01
title: 用户修改邮箱
run: True
severity: normal
url: api/v1/${login}/update_email.json
method: PATCH
headers:
Content-Type: application/json; charset=utf-8;
Authorization: ${token_type} ${access_token}
cookies:
request_type: json
payload:
email: ${generate_email()}
password: ${password}
code: ${green_code}
files:
assert_response:
status_code: 200
assert_status:
message: 断言接口status=0
expect_value: 0
assert_type: ==
type_jsonpath: $.status
assert_message:
message: 断言接口message=success
expect_value: success
assert_type: ==
type_jsonpath: $.message
assert_sql:
extract:

View File

@@ -0,0 +1,80 @@
# 公共参数
case_common:
allure_epic: GitLink接口
allure_feature: 用户
allure_story: 账号管理
case_markers:
- gitlink
- gitea
- change_pwd
- login: 登录接口
- usefixtures: get_oauth_token
- skip: 跳过执行该用例
# 用例数据
case_info:
-
id: gitlink_user_change_password_01
title: 用户修改密码, 新密码和确认密码一致,修改成功
run: True
severity: normal
url: /api/accounts/change_password.json
method: POST
headers:
Content-Type: application/json; charset=utf-8;
Authorization: ${token_type} ${access_token}
cookies:
request_type: json
payload:
login: ${login}
old_password: ${password} # 原始密码
password: ${password} # 新密码
new_password_repeat: ${password} # 确认密码
files:
assert_response:
status_code: 200
assert_status:
message: 断言接口status=0
expect_value: 0
assert_type: ==
type_jsonpath: $.status
assert_message:
message: 断言接口message=success
expect_value: success
assert_type: ==
type_jsonpath: $.message
assert_sql:
extract:
-
id: gitlink_user_change_password_02
title: 用户修改密码, 新密码和确认密码不一致,修改失败
run: True
severity: normal
url: /api/accounts/change_password.json
method: POST
headers:
Content-Type: application/json; charset=utf-8;
Authorization: ${token_type} ${access_token}
cookies:
request_type: json
payload:
login: ${login}
old_password: ${password} # 原始密码
password: ${generate_identifier()} # 新密码
new_password_repeat: ${generate_identifier()} # 确认密码
files:
assert_response:
status_code: 200
assert_status:
message: 断言接口status=-2
expect_value: -2
assert_type: ==
type_jsonpath: $.status
assert_message:
message: 断言接口message=success
expect_value: 新密码与确认密码不一致
assert_type: ==
type_jsonpath: $.message
assert_sql:
extract:

View File

@@ -0,0 +1,44 @@
# 公共参数
case_common:
allure_epic: GitLink接口
allure_feature: 用户
allure_story: 账号管理
case_markers:
- gitlink
- change_phone
- login: 登录接口
- usefixtures: get_oauth_token
# 用例数据
case_info:
-
id: gitlink_user_change_phone_01
title: 用户修改手机号码
run: True
severity: normal
url: api/v1/${login}/update_phone.json
method: PATCH
headers:
Content-Type: application/json; charset=utf-8;
Authorization: ${token_type} ${access_token}
cookies:
request_type: json
payload:
phone: ${generate_phone(lan='zh')}
password: ${password}
code: ${green_code}
files:
assert_response:
status_code: 200
assert_status:
message: 断言接口status=0
expect_value: 0
assert_type: ==
type_jsonpath: $.status
assert_message:
message: 断言接口message=success
expect_value: success
assert_type: ==
type_jsonpath: $.message
assert_sql:
extract:

2
run.py
View File

@@ -70,7 +70,7 @@ def run(env, m, report):
""")
# ------------------------ 处理一下获取到的参数----------------------------
# 根据指定的环境参数将运行环境所需相关配置数据保存到GLOBAL_VARS
# # 根据指定的环境参数将运行环境所需相关配置数据保存到GLOBAL_VARS
ENV_VARS["common"]["env"] = ENV_VARS[env]["host"]
GLOBAL_VARS.update(ENV_VARS["common"])
GLOBAL_VARS.update(ENV_VARS[env])

View File

@@ -4,16 +4,17 @@
# @File : conftest.py
# @Software: PyCharm
# @Desc:
import os.path
# 标准库导入
import os
# 第三方库导入
import pytest
import allure
from loguru import logger
# 本地应用/模块导入
from config.global_vars import GLOBAL_VARS
from config.path_config import DATA_DIR
from config.path_config import GITLINK_DIR
from utils.report_utils.allure_handle import allure_title
from utils.requests_utils.api_workflow import get_api_data, api_work_flow
@@ -26,7 +27,7 @@ def case_control(request):
case = request.getfixturevalue("case")
_case = "\n" + "=" * 80 \
+ "\n-----------------------------START-开始执行用例-----------------------------\n" \
"\n-------------用例数据--------------------\n" \
"\n-------------用例数据--------------------\n" \
f"ID: {case.get('id')}\n" \
f"title: {case.get('title')}\n" \
f"run: {case.get('run')}\n" \
@@ -78,6 +79,39 @@ def gitlink_login():
:return:
"""
# 请求登录接口
login_api = get_api_data(os.path.join(DATA_DIR, "gitlink", "test_login.yaml"), "gitlink_login_01")
login_api = get_api_data(os.path.join(GITLINK_DIR, "test_login.yaml"), "gitlink_login_01")
api_work_flow(login_api, GLOBAL_VARS)
@pytest.fixture(scope="session")
def get_oauth_token():
"""
获取oauth_token 用于在接口的headers里面传递{AuthorizationBearer {{token}}}
"""
login_oauth_token_api = get_api_data(os.path.join(GITLINK_DIR, "login_oauth_token.yaml"),
"gitlink_login_oauth_token_01")
api_work_flow(login_oauth_token_api, GLOBAL_VARS)
@pytest.fixture(scope="session")
def delete_project():
"""
删除测试项目,清理测试数据
"""
yield
delete_project_api = get_api_data(os.path.join(GITLINK_DIR, "projects", "test_delete_project.yaml"),
"gitlink_projects_delete_project_01")
api_work_flow(delete_project_api, GLOBAL_VARS)
@pytest.fixture(scope="session")
def new_project(get_oauth_token):
"""
新建测试项目,用于测试
"""
new_project_api = get_api_data(os.path.join(GITLINK_DIR, "projects", "test_new_project.yaml"),
"gitlink_projects_new_project_01")
api_work_flow(new_project_api, GLOBAL_VARS)

View File

@@ -75,9 +75,7 @@ class AssertUtils:
if "type_re" in self.assert_data and self.assert_data["type_re"]:
return re_extract(obj=self.response.text, expr=self.assert_data["type_re"])
else:
assert 'type_re' or 'type_jsonpath' in self.assert_data.keys(), (
" 断言数据: '%s' 中缺少 `type_re` 或 `type_jsonpath` 属性 " % self.assert_data
)
return self.response.text
def get_actual_value_by_sql(self):
"""

View File

@@ -169,7 +169,7 @@ class FakerData:
email = self.faker.email()
return email
def generate_identifier(self, lan="en"):
def generate_identifier(self, lan="en", char_len=8):
"""
:return:生成随机标识满足要求长度为2~100 只能包含数字,字母,下划线(_),中划线(-),英文句号(.),必须以数字和字母开头,不能以下划线/中划线/英文句号开头和结尾
"""
@@ -184,8 +184,35 @@ class FakerData:
re.match(r'^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,98}[a-zA-Z0-9]$', identifier) and
not (identifier.startswith('_') or identifier.startswith('-') or identifier.startswith('.')) and
not (identifier.endswith('_') or identifier.endswith('.'))
):
return identifier
) and len(identifier) >= char_len:
return identifier[:char_len]
def generate_city(self, lan="en", full: bool = True) -> str:
"""
:return: 随机生成城市名
"""
if lan == "zh":
faker = self.fk_zh
else:
faker = self.faker
if full:
city = faker.city()
else:
city = faker.city_name()
return city
def generate_province(self, lan="en") -> str:
"""
:return: 随机生成城市名
"""
if lan == "zh":
faker = self.fk_zh
else:
faker = self.faker
return faker.province()
@classmethod
def generate_time(cls, fmt='%Y-%m-%d %H:%M:%S') -> str: