更改用例通过率计算方式;添加插件pytest-repeat,支持用例重复执行;增加数据处理方法:获取图片base64格式,支持用例数据传参需求;
This commit is contained in:
29
Pipfile
29
Pipfile
@@ -1,26 +1,25 @@
|
||||
[[source]]
|
||||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
verify_ssl = false
|
||||
name = "pip_conf_index_global"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
pymysql = "==1.1.0"
|
||||
loguru = "==0.7.2"
|
||||
requests-toolbelt = "==1.0.0"
|
||||
requests = "*"
|
||||
openpyxl = "==3.1.2"
|
||||
sshtunnel = "==0.4.0"
|
||||
yagmail = "==0.15.293"
|
||||
pyyaml = "==6.0.1"
|
||||
allure-pytest = "==2.9.45"
|
||||
click = "==8.1.7"
|
||||
faker = "==21.0.0"
|
||||
jsonpath = "0.82.2"
|
||||
pytest = "==6.2.5"
|
||||
pytest-rerunfailures = "==12.0"
|
||||
allure-pytest = "==2.9.45"
|
||||
jsonpath = "==0.82.2"
|
||||
loguru = "==0.7.2"
|
||||
openpyxl = "==3.1.2"
|
||||
pydantic = "==2.5.2"
|
||||
xpinyin = "==0.7.6"
|
||||
pymysql = "==1.1.0"
|
||||
pytest-rerunfailures = "==12.0"
|
||||
pyyaml = "==6.0.1"
|
||||
requests-toolbelt = "==1.0.0"
|
||||
"ruamel.yaml" = "==0.18.5"
|
||||
sshtunnel = "==0.4.0"
|
||||
xpinyin = "==0.7.6"
|
||||
yagmail = "==0.15.293"
|
||||
pytest-repeat = "==0.9.3"
|
||||
|
||||
[dev-packages]
|
||||
|
||||
|
||||
38
README.md
38
README.md
@@ -27,6 +27,7 @@
|
||||
|
||||
* 通过session会话方式,解决了登录之后cookie关联处理`
|
||||
* 动态多断言: 如接口需要同时校验响应数据和sql校验,支持多场景断言
|
||||
* 支持单独调试用例,支持用例的重复执行
|
||||
* 框架天然支持接口动态传参、关联灵活处理
|
||||
* 支持测试数据分析,测试数据不符合规范有预警机制
|
||||
* 支持通过用例数据动态配置pytest.mark, 包括自定义标记,pytest.mark.skip以及pytest,mark.usefixtures
|
||||
@@ -45,23 +46,22 @@
|
||||
|
||||
## 三、依赖库
|
||||
```
|
||||
pymysql = "*"
|
||||
loguru = "*"
|
||||
requests-toolbelt = "*"
|
||||
requests = "*"
|
||||
openpyxl = "*"
|
||||
sshtunnel = "*"
|
||||
yagmail = "*"
|
||||
pyyaml = "*"
|
||||
click = "*"
|
||||
faker = "*"
|
||||
jsonpath = "*"
|
||||
pytest = "==6.2.5"
|
||||
pytest-rerunfailures = "*"
|
||||
allure-pytest = "==2.9.45"
|
||||
pydantic = "*"
|
||||
xpinyin = "*"
|
||||
"ruamel.yaml" = "*"
|
||||
click = "==8.1.7"
|
||||
faker = "==21.0.0"
|
||||
jsonpath = "==0.82.2"
|
||||
loguru = "==0.7.2"
|
||||
openpyxl = "==3.1.2"
|
||||
pydantic = "==2.5.2"
|
||||
pymysql = "==1.1.0"
|
||||
pytest-rerunfailures = "==12.0"
|
||||
pyyaml = "==6.0.1"
|
||||
requests-toolbelt = "==1.0.0"
|
||||
"ruamel.yaml" = "==0.18.5"
|
||||
sshtunnel = "==0.4.0"
|
||||
xpinyin = "==0.7.6"
|
||||
yagmail = "==0.15.293"
|
||||
pytest-repeat = "*"
|
||||
```
|
||||
|
||||
|
||||
@@ -421,6 +421,12 @@ excel表单2名称是:示例模块
|
||||
顾名思义,虚拟环境就是虚拟出来的一个隔离的Python环境,每个项目都可以有自己的虚拟环境,用pip安装各自的第三方包,不同项目之间也不会存在冲突。
|
||||
创建虚拟环境需要一些工具, 我们使用pipenv来创建虚拟环境和管理依赖包。
|
||||
|
||||
- [如何调试单个用例?](https://www.gitlink.org.cn/zone/tester/newdetail/512)
|
||||
有些小伙伴在测试的时候,想要单独调试用例,但是不清楚如何调试。本文将详细讲解~
|
||||
|
||||
- [如何重复执行用例?](https://www.gitlink.org.cn/zone/tester/newdetail/514)
|
||||
平常在做功能测试的时候,经常会遇到某个模块不稳定,偶然会出现一些bug,对于这种问题我们会针对此用例反复执行多次,最终复现出问题来。
|
||||
自动化运行用例时候,也会出现偶然的bug,可以针对单个用例重复执行多次。
|
||||
|
||||
|
||||
## 九、初始化项目可能遇到的问题
|
||||
|
||||
@@ -18,6 +18,7 @@ ENV_VARS = {
|
||||
"test": {
|
||||
# 示例测试环境及示例测试账号
|
||||
"host": "https://testforgeplus.trustie.net",
|
||||
"wiki_host": "",
|
||||
"client_id": "****client_id-test****", # 获取oauth_token需要的参数
|
||||
"client_secret": "****client_secret-test****", # 获取oauth_token需要的参数
|
||||
"green_code": "****green_code-test****", # 万能验证码
|
||||
@@ -26,7 +27,7 @@ ENV_VARS = {
|
||||
"nickname": "autotest",
|
||||
"user_id": 106,
|
||||
"super_login": "floraachy",
|
||||
"super_password": "****floraachy-test****", # 运行时需要手动更改密码
|
||||
"super_password": "****floraachy-test****", # 运行时需要手动更改密码
|
||||
"project_url": "/autotest/auotest",
|
||||
"db_info": {
|
||||
"db_host": "xx.xx.xx.xx",
|
||||
@@ -46,6 +47,7 @@ ENV_VARS = {
|
||||
"pre": {
|
||||
# 示例测试环境及示例测试账号
|
||||
"host": "http://172.20.32.202:4000",
|
||||
"wiki_host": "",
|
||||
"client_id": "****client_id-pre****", # 获取oauth_token需要的参数
|
||||
"client_secret": "****client_secret-pre****", # 获取oauth_token需要的参数
|
||||
"green_code": "****green_code-pre****", # 万能验证码
|
||||
@@ -54,7 +56,7 @@ ENV_VARS = {
|
||||
"nickname": "autotest",
|
||||
"user_id": 115,
|
||||
"super_login": "floraachy",
|
||||
"super_password": "****floraachy-pre****", # 运行时需要手动更改密码
|
||||
"super_password": "****floraachy-pre****", # 运行时需要手动更改密码
|
||||
"project_url": "/floraachy/autotest",
|
||||
"db_info": {
|
||||
"db_host": "xx.xx.xx.xx",
|
||||
@@ -73,15 +75,16 @@ ENV_VARS = {
|
||||
},
|
||||
"live": {
|
||||
"host": "https://www.gitlink.org.cn",
|
||||
"wiki_host": "",
|
||||
"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****", # 运行时需要手动更改密码
|
||||
"super_password": "****chenyh-live****", # 运行时需要手动更改密码
|
||||
"project_url": "/floraachy/auotest",
|
||||
"db_info": {
|
||||
"db_host": "xx.xx.xx.xx",
|
||||
|
||||
@@ -78,7 +78,7 @@ def pytest_terminal_summary(terminalreporter, config):
|
||||
f"- 异常用例个数(error): {_ERROR} 个\n" \
|
||||
f"- 重跑的用例数(--reruns的值): {_RERUN} ({reruns_value}) 个\n"
|
||||
try:
|
||||
_RATE = _PASSED / (_TOTAL - _SKIPPED) * 100
|
||||
_RATE = (_PASSED + _XPASSED )/ (_PASSED + _FAILED + _XPASSED + _XFAILED) * 100
|
||||
test_result = f"- 用例成功率: {_RATE:.2f} %\n"
|
||||
logger.success(f"{test_info}{test_result}")
|
||||
except ZeroDivisionError:
|
||||
|
||||
44
interface/gitlink/organization/test_delete_organization.yaml
Normal file
44
interface/gitlink/organization/test_delete_organization.yaml
Normal file
@@ -0,0 +1,44 @@
|
||||
case_common:
|
||||
allure_epic: GitLink接口
|
||||
allure_feature: 开源项目模块
|
||||
allure_story: 组织
|
||||
case_markers:
|
||||
- gitlink
|
||||
- projects
|
||||
- gitea
|
||||
- delete_organization
|
||||
- usefixtures: get_oauth_token
|
||||
|
||||
case_info:
|
||||
-
|
||||
id: gitlink_projects_delete_organization_01
|
||||
title: 删除组织
|
||||
severity: critical
|
||||
run: True
|
||||
url: /api/organizations/${org_id}.json
|
||||
method: DELETE
|
||||
headers:
|
||||
Content-Type: application/json; charset=utf-8;
|
||||
Authorization: ${token_type} ${access_token}
|
||||
cookies:
|
||||
request_type: params
|
||||
payload:
|
||||
password: ${password} # 用户登录密码
|
||||
files:
|
||||
assert_response:
|
||||
status_code: 200
|
||||
assertMessage:
|
||||
message: 断言响应message=success
|
||||
assert_type: ==
|
||||
expect_value: success
|
||||
type_jsonpath: $.message
|
||||
assertStatus:
|
||||
message: 断言响应status=0
|
||||
assert_type: ==
|
||||
expect_value: 0
|
||||
type_jsonpath: $.status
|
||||
assert_sql:
|
||||
extract:
|
||||
case_dependence:
|
||||
setup:
|
||||
interface: gitlink_projects_new_organization_01
|
||||
@@ -1,4 +1,3 @@
|
||||
# 公共参数
|
||||
case_common:
|
||||
allure_epic: GitLink接口
|
||||
allure_feature: 开源项目模块
|
||||
@@ -9,9 +8,7 @@ case_common:
|
||||
- gitea
|
||||
- new_organization
|
||||
- usefixtures: get_oauth_token
|
||||
- skip: 参数:image还没处理好,暂时略过
|
||||
|
||||
# 用例数据
|
||||
case_info:
|
||||
-
|
||||
id: gitlink_projects_new_organization_01
|
||||
@@ -31,7 +28,7 @@ case_info:
|
||||
description: ${generate_paragraph()} # 组织描述
|
||||
location: ${generate_city(full=False)} # 组织地区
|
||||
repo_admin_change_team_access: true # 项目管理员可以添加或移除团队的访问权限
|
||||
image: ${} # 组织图片
|
||||
image: data:image/png;base64,${get_file_content('gitlinklogo3.jpg')} # 组织图片, base64编码方式
|
||||
visibility: common # 组织可见性,默认值common
|
||||
files:
|
||||
assert_response:
|
||||
@@ -41,4 +38,9 @@ case_info:
|
||||
assert_type: contains
|
||||
expect_value: id
|
||||
assert_sql:
|
||||
extract:
|
||||
extract:
|
||||
type_jsonpath:
|
||||
org_id: $.id
|
||||
case_dependence:
|
||||
teardown:
|
||||
interface: gitlink_projects_delete_organization_01
|
||||
6
interface/gitlink/projects/issues/__init__.py
Normal file
6
interface/gitlink/projects/issues/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2023/11/14 9:56
|
||||
# @Author : floraachy
|
||||
# @File : __init__.py
|
||||
# @Software: PyCharm
|
||||
# @Desc:
|
||||
26
interface/gitlink/projects/issues/get_issue_detail.yaml
Normal file
26
interface/gitlink/projects/issues/get_issue_detail.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
case_common:
|
||||
allure_epic: 开源项目
|
||||
allure_feature: 项目
|
||||
allure_story: 疑修(Issue)
|
||||
case_markers:
|
||||
- gitlink
|
||||
- project
|
||||
- issue
|
||||
|
||||
case_info:
|
||||
-
|
||||
id: project_get_issue_detail
|
||||
title: 项目内获取疑修详情接口
|
||||
run: True
|
||||
severity: normal
|
||||
url: /api/v1/${project_url}/issues/${issue_id}
|
||||
method: GET
|
||||
headers: {"Content-Type": "application/json; charset=utf-8;"}
|
||||
cookies: ${login_cookies}
|
||||
request_type: json
|
||||
payload:
|
||||
files:
|
||||
assert_response:
|
||||
status_code: 200
|
||||
assert_sql:
|
||||
extract:
|
||||
@@ -0,0 +1,26 @@
|
||||
case_common:
|
||||
allure_epic: 开源项目
|
||||
allure_feature: 项目
|
||||
allure_story: 疑修(Issue)
|
||||
case_markers:
|
||||
- gitlink
|
||||
- project
|
||||
- issue
|
||||
|
||||
case_info:
|
||||
-
|
||||
id: project_get_issue_journals_detail
|
||||
title: 项目内获取疑修列表接口
|
||||
run: True
|
||||
severity: normal
|
||||
url: /api/v1/${project_url}/issues/{issue_id}/journals?category=comment&page=${page}&limit=${limit}
|
||||
method: GET
|
||||
headers: {"Content-Type": "application/json; charset=utf-8;"}
|
||||
cookies: ${login_cookies}
|
||||
request_type: json
|
||||
payload:
|
||||
files:
|
||||
assert_response:
|
||||
status_code: 200
|
||||
assert_sql:
|
||||
extract:
|
||||
26
interface/gitlink/projects/issues/get_issue_list.yaml
Normal file
26
interface/gitlink/projects/issues/get_issue_list.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
case_common:
|
||||
allure_epic: 开源项目
|
||||
allure_feature: 项目
|
||||
allure_story: 疑修(Issue)
|
||||
case_markers:
|
||||
- gitlink
|
||||
- project
|
||||
- issue
|
||||
|
||||
case_info:
|
||||
-
|
||||
id: project_get_issue_list
|
||||
title: 项目内获取疑修列表接口
|
||||
run: True
|
||||
severity: normal
|
||||
url: /api/v1/${project_url}/issues?participant_category=all&category=all&limit=${limit}&page=${page}
|
||||
method: GET
|
||||
headers: {"Content-Type": "application/json; charset=utf-8;"}
|
||||
cookies: ${login_cookies}
|
||||
request_type: json
|
||||
payload:
|
||||
files:
|
||||
assert_response:
|
||||
status_code: 200
|
||||
assert_sql:
|
||||
extract:
|
||||
29
interface/gitlink/projects/issues/new_issue_journals.yaml
Normal file
29
interface/gitlink/projects/issues/new_issue_journals.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
case_common:
|
||||
allure_epic: 开源项目
|
||||
allure_feature: 项目
|
||||
allure_story: 疑修(Issue)
|
||||
case_markers:
|
||||
- gitlink
|
||||
- project
|
||||
- issue
|
||||
|
||||
case_info:
|
||||
-
|
||||
id: project_new_issue_journals
|
||||
title: 项目内新建疑修评论接口
|
||||
run: True
|
||||
severity: normal
|
||||
url: /api/v1/${project_url}/issues/${issue_id}/journals
|
||||
method: POST
|
||||
headers: {"Content-Type": "application/json; charset=utf-8;"}
|
||||
cookies: ${login_cookies}
|
||||
request_type: json
|
||||
payload:
|
||||
parent_id: 0
|
||||
note:
|
||||
receivers_login: [ ]
|
||||
files:
|
||||
assert_response:
|
||||
status_code: 200
|
||||
assert_sql:
|
||||
extract:
|
||||
@@ -0,0 +1,30 @@
|
||||
case_common:
|
||||
allure_epic: 开源项目
|
||||
allure_feature: 项目
|
||||
allure_story: 疑修(Issue)
|
||||
case_markers:
|
||||
- gitlink
|
||||
- project
|
||||
- issue
|
||||
|
||||
case_info:
|
||||
-
|
||||
id: project_new_issue_journals
|
||||
title: 项目内新建疑修评论回复接口
|
||||
run: True
|
||||
severity: normal
|
||||
url: /api/v1/${project_url}/issues/${issue_id}/journals
|
||||
method: POST
|
||||
headers: {"Content-Type": "application/json; charset=utf-8;"}
|
||||
cookies: ${login_cookies}
|
||||
request_type: json
|
||||
payload:
|
||||
parent_id:
|
||||
reply_id:
|
||||
note:
|
||||
receivers_login: []
|
||||
files:
|
||||
assert_response:
|
||||
status_code: 200
|
||||
assert_sql:
|
||||
extract:
|
||||
54
interface/gitlink/projects/issues/test_new_issue.yaml
Normal file
54
interface/gitlink/projects/issues/test_new_issue.yaml
Normal file
@@ -0,0 +1,54 @@
|
||||
case_common:
|
||||
allure_epic: GitLink接口
|
||||
allure_feature: 开源项目模块
|
||||
allure_story: 疑修(Issue)
|
||||
case_markers:
|
||||
- gitlink
|
||||
- project
|
||||
- issue
|
||||
- new_issue
|
||||
- usefixtures: gitlink_login
|
||||
- repeat(20)
|
||||
|
||||
case_info:
|
||||
-
|
||||
id: project_new_issue_001
|
||||
title: 项目内新建疑修接口
|
||||
run: True
|
||||
severity: normal
|
||||
url: /api/v1/${project_url}/issues
|
||||
method: POST
|
||||
headers: {"Content-Type": "application/json; charset=utf-8;"}
|
||||
cookies: ${cookies}
|
||||
request_type: json
|
||||
payload:
|
||||
subject: ${generate_company_name(lan='zh', fix='pre')}_${generate_words}
|
||||
description: ${generate_paragraph}
|
||||
branch_name: master
|
||||
status_id: 1
|
||||
priority_id: ${random.choice([1,2,3,4,5])}
|
||||
milestone_id:
|
||||
issue_tag_ids:
|
||||
assigner_ids:
|
||||
attachment_ids: # ["768f752b-2037-4b11-93e4-ccc8d72d2a54", "f5141121-6791-49b7-9334-79ebdbffeb3e"]
|
||||
- ${attachment_id}
|
||||
start_date: ${generate_today_date}
|
||||
due_date: {generate_time_after_week}
|
||||
receivers_login: []
|
||||
files:
|
||||
assert_response:
|
||||
status_code: 200
|
||||
assertId:
|
||||
message: 断言接口响应数据存在id
|
||||
assert_type: contains
|
||||
expect_value: id
|
||||
assert_sql:
|
||||
extract:
|
||||
type_jsonpath:
|
||||
issue_index: $.project_issues_index
|
||||
issue_title: $.subject
|
||||
issue_desc: $.description
|
||||
issue_files: $.attachments..title
|
||||
case_dependence:
|
||||
setup:
|
||||
interface: gitlink_upload_file_01
|
||||
@@ -25,7 +25,6 @@ case_info:
|
||||
payload:
|
||||
ref: master
|
||||
filepath:
|
||||
type: # 可选file或者dir
|
||||
files:
|
||||
assert_response:
|
||||
status_code: 200
|
||||
|
||||
@@ -18,7 +18,7 @@ case_info:
|
||||
url: /api/attachments.json
|
||||
method: POST
|
||||
headers:
|
||||
cookies: ${login_cookie}
|
||||
cookies: ${cookie}
|
||||
cookies:
|
||||
request_type: file
|
||||
payload:
|
||||
@@ -28,4 +28,4 @@ case_info:
|
||||
assert_sql:
|
||||
extract:
|
||||
type_jsonpath:
|
||||
file_id: $.id
|
||||
attachment_id: $.id
|
||||
|
||||
51
interface/gitlink/projects/wiki/test_new_wiki.yaml
Normal file
51
interface/gitlink/projects/wiki/test_new_wiki.yaml
Normal file
@@ -0,0 +1,51 @@
|
||||
case_common:
|
||||
allure_epic: GitLink接口
|
||||
allure_feature: 开源项目模块
|
||||
allure_story: Wiki
|
||||
case_markers:
|
||||
- gitlink
|
||||
- projects
|
||||
- gitea
|
||||
- new_wiki
|
||||
- usefixtures: gitlink_login
|
||||
|
||||
case_info:
|
||||
-
|
||||
id: gitlink_projects_new_wiki_01
|
||||
title: 新建wiki页面
|
||||
severity: critical
|
||||
run: True
|
||||
url: ${wiki_host}/api/wiki/createWiki
|
||||
method: POST
|
||||
headers:
|
||||
Content-Type: application/json; charset=utf-8;
|
||||
cookies: ${cookie}
|
||||
cookies:
|
||||
request_type: json
|
||||
payload:
|
||||
owner: ${repo_owner}
|
||||
repo: ${repo_identifier}
|
||||
projectId: ${project_id}
|
||||
pageName: 2023
|
||||
title: 2023
|
||||
message:
|
||||
content_base64: 5qyi6L+O5p2l5YiwV2lraQ==
|
||||
files:
|
||||
assert_response:
|
||||
status_code: 200
|
||||
commit_count:
|
||||
message: 断言接口返回的commit_count
|
||||
expect_value: 1
|
||||
assert_type: ==
|
||||
type_jsonpath: $.data.commit_count
|
||||
assertMessage:
|
||||
message: 断言接口返回的message
|
||||
expect_value: 201
|
||||
assert_type: ==
|
||||
type_jsonpath: $.message
|
||||
assert_sql:
|
||||
extract:
|
||||
case_dependence:
|
||||
setup:
|
||||
interface:
|
||||
- gitlink_projects_new_project_01
|
||||
@@ -5,6 +5,7 @@ case_common:
|
||||
allure_story: 登录接口 # 故事,可以理解为场景,相当于method级的标签, 往下是 title
|
||||
case_markers: # pytest框架的标记 pytest.mark.
|
||||
- gitlink
|
||||
- smoke
|
||||
- login: 登录接口
|
||||
|
||||
# 用例数据
|
||||
|
||||
@@ -9,4 +9,5 @@ addopts =
|
||||
disable_test_id_escaping_and_forfeit_all_rights_to_community_support = True
|
||||
markers =
|
||||
auto: auto generate case
|
||||
test_demo: demo case
|
||||
test_demo: demo case
|
||||
smoke:smoke
|
||||
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
@@ -89,7 +89,8 @@ def gitlink_login():
|
||||
"""
|
||||
# 请求登录接口
|
||||
login_api = get_api_data(os.path.join(GITLINK_DIR, "test_login.yaml"), "gitlink_login_01")
|
||||
api_work_flow(login_api, GLOBAL_VARS)
|
||||
res = api_work_flow(login_api, GLOBAL_VARS)
|
||||
GLOBAL_VARS.update(res)
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
@@ -100,4 +101,5 @@ def get_oauth_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)
|
||||
res = api_work_flow(login_oauth_token_api, GLOBAL_VARS)
|
||||
GLOBAL_VARS.update(res)
|
||||
@@ -31,7 +31,7 @@ class AssertUtils:
|
||||
|
||||
self.assert_data = assert_data
|
||||
self.response = response
|
||||
if db_info:
|
||||
if assert_data and db_info:
|
||||
self.db_connect = MysqlServer(**db_info)
|
||||
|
||||
@property
|
||||
|
||||
@@ -177,7 +177,7 @@ def gen_case_file(filename, case_template_path, case_common, case_data, target_c
|
||||
os.makedirs(target_case_path, exist_ok=True)
|
||||
# 获取用例数据中的标记
|
||||
case_markers = case_common.get("case_markers", []) or []
|
||||
logger.trace(f"从用例中拿到的标记有:{case_markers}, {type(case_markers)}")
|
||||
logger.debug(f"从用例中拿到的标记有:{case_markers}, {type(case_markers)}")
|
||||
# 先读取用例模板中每一行的内容
|
||||
with open(file=case_template_path, mode="r", encoding="utf-8") as f:
|
||||
case_template = f.readlines()
|
||||
@@ -187,7 +187,7 @@ def gen_case_file(filename, case_template_path, case_common, case_data, target_c
|
||||
# 这里是预计往 @pytest.mark.parametrize( 这一行的上面插入标记
|
||||
if content.strip().startswith('@pytest.mark.parametrize('):
|
||||
# 往测试用例模板中插入自定义标记
|
||||
logger.trace(f"获取到的case_markers:{case_markers}, {type(case_markers)}")
|
||||
logger.debug(f"获取到的case_markers:{case_markers}, {type(case_markers)}")
|
||||
for case_marker in case_markers:
|
||||
# 获取符合要求格式的自定义标记名称,并插入到测试模板中
|
||||
marker = is_valid_marker(case_marker)
|
||||
@@ -237,6 +237,12 @@ def is_valid_marker(markers):
|
||||
CUSTOM_MARKERS.append(markers)
|
||||
# 返回合法有效的标记名称,用于添加到测试方法中
|
||||
return markers
|
||||
elif "repeat" in markers:
|
||||
if re.match(r'repeat\(\d+\)', markers):
|
||||
return markers
|
||||
else:
|
||||
logger.error(f"{markers} 格式不合法, 正确格式参考:repeat(2)")
|
||||
return False
|
||||
else:
|
||||
logger.error(f"{markers} 格式不合法, 建议仅输入数字,字母,下划线组合,且不能以数字,下划线开头")
|
||||
return False
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# @File : data_handle.py
|
||||
# @Software: PyCharm
|
||||
# @Desc:
|
||||
|
||||
import os.path
|
||||
# 标准库导入
|
||||
import random # 导包不能移除,否则random.choice这种就不能处理了
|
||||
import json
|
||||
@@ -18,6 +18,8 @@ from requests.utils import dict_from_cookiejar
|
||||
# 本地应用/模块导入
|
||||
from utils.data_utils.faker_handle import FakerData
|
||||
from utils.data_utils.eval_data_handle import eval_data
|
||||
from utils.files_utils.files_handle import file_to_base64, get_files
|
||||
from config.path_config import FILES_DIR
|
||||
|
||||
|
||||
class DataHandle:
|
||||
@@ -175,10 +177,34 @@ class DataHandle:
|
||||
msg = (f"\nobj --> {obj}\n"
|
||||
f"函数返回值 --> {res}\n"
|
||||
f"函数返回值类型 --> {type(res)}\n")
|
||||
logger.warning(f"\nWarn: --------处理函数方法后,尝试eval({obj})失败,可能原始的字符串并不是python表达式-------{msg}")
|
||||
logger.warning(
|
||||
f"\nWarn: --------处理函数方法后,尝试eval({obj})失败,可能原始的字符串并不是python表达式-------{msg}")
|
||||
return obj
|
||||
|
||||
|
||||
def get_file_content(file_name):
|
||||
"""
|
||||
获取文件二进制内容
|
||||
:param file_name: 文件名称
|
||||
:return:
|
||||
"""
|
||||
file_path = os.path.join(FILES_DIR, file_name)
|
||||
if os.path.exists(file_path):
|
||||
# 如果文件是一个真实存在的路径,则返回文件二进制内容
|
||||
return file_to_base64(file_path=file_path)
|
||||
else:
|
||||
# 若文件不存在,则尝试以文件扩展名随机选择一个文件
|
||||
logger.warning(f"图片不存在,将获取传入文件名后缀,随机取对应类型的文件, 路径:{file_path}")
|
||||
file_extension = os.path.splitext(file_name)[1]
|
||||
files = get_files(target=FILES_DIR, end=file_extension)
|
||||
if files:
|
||||
# 返回文件二进制内容
|
||||
return file_to_base64(file_path=random.choice(files))
|
||||
else:
|
||||
logger.warning(f"找不到该文件后缀对应的同类型文件,将返回空, 传入的文件名:{file_name}")
|
||||
return None
|
||||
|
||||
|
||||
# 声明data_handle方法,这样外部就可以直接import data_handle来使用了
|
||||
data_handle = DataHandle().data_handle
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ def json_extractor(obj, expr: str = '.'):
|
||||
"""
|
||||
try:
|
||||
result = jsonpath(obj, expr)[0] if len(jsonpath(obj, expr)) == 1 else jsonpath(obj, expr)
|
||||
result = data_handle(obj=result)
|
||||
logger.debug(f"\n提取对象:{obj}\n"
|
||||
f"提取表达式: {expr} \n"
|
||||
f"提取值类型: {type(result)}\n"
|
||||
|
||||
@@ -5,10 +5,13 @@
|
||||
# @Software: PyCharm
|
||||
# @Desc: 处理文件相关操作
|
||||
|
||||
# 第三方库导入
|
||||
from loguru import logger
|
||||
# 标准库导入
|
||||
import os
|
||||
import zipfile
|
||||
import shutil
|
||||
import base64
|
||||
|
||||
|
||||
def get_files(target, start=None, end=None):
|
||||
@@ -77,7 +80,7 @@ def zip_file(in_path: str, out_path: str):
|
||||
"""
|
||||
# 如果传入的路径是一个目录才进行压缩操作
|
||||
if os.path.isdir(in_path):
|
||||
print(f"目标路径:{in_path} 是一个目录,开始进行压缩......")
|
||||
logger.debug(f"目标路径:{in_path} 是一个目录,开始进行压缩......")
|
||||
# 写入
|
||||
zip = zipfile.ZipFile(out_path, "w", zipfile.ZIP_DEFLATED)
|
||||
for path, dirnames, filenames in os.walk(in_path):
|
||||
@@ -89,9 +92,9 @@ def zip_file(in_path: str, out_path: str):
|
||||
path, filename), os.path.join(
|
||||
fpath, filename))
|
||||
zip.close()
|
||||
print(f"目标路径:{in_path} 压缩完成!, 压缩文件路径:{out_path}")
|
||||
logger.debug(f"目标路径:{in_path} 压缩完成!, 压缩文件路径:{out_path}")
|
||||
else:
|
||||
print(f"目标路径:{in_path} 不是一个目录,请检查!")
|
||||
logger.debug(f"目标路径:{in_path} 不是一个目录,请检查!")
|
||||
|
||||
|
||||
def delete_dir_file(file_path):
|
||||
@@ -101,7 +104,7 @@ def delete_dir_file(file_path):
|
||||
"""
|
||||
paths = os.listdir(file_path)
|
||||
if paths:
|
||||
print(f"目标目录: {file_path} 存在文件或目录,进行删除操作")
|
||||
logger.debug(f"目标目录: {file_path} 存在文件或目录,进行删除操作")
|
||||
for item in paths:
|
||||
path = os.path.join(file_path, item)
|
||||
# 如果目标路径是一个文件,使用os.remove删除
|
||||
@@ -111,7 +114,7 @@ def delete_dir_file(file_path):
|
||||
if os.path.isdir(path):
|
||||
os.rmdir(path)
|
||||
else:
|
||||
print(f"目标目录: {file_path} 不存在文件或目录,不需要删除")
|
||||
logger.debug(f"目标目录: {file_path} 不存在文件或目录,不需要删除")
|
||||
|
||||
|
||||
def copy_file(src_file_path, dest_dir_path):
|
||||
@@ -161,3 +164,15 @@ def get_relative_path(file_path, directory_path):
|
||||
relative_path = os.path.relpath(os.path.abspath(file_path), os.path.abspath(directory_path))
|
||||
# 如果相对路径中包含文件名,则去除文件名部分并返回
|
||||
return os.path.dirname(relative_path)
|
||||
|
||||
|
||||
def file_to_base64(file_path):
|
||||
"""
|
||||
使用Python的标准库base64来读取文件内容并将其转换为base64编码
|
||||
"""
|
||||
if os.path.exists(file_path):
|
||||
with open(file_path, "rb") as file:
|
||||
encoded_string = base64.b64encode(file.read())
|
||||
return encoded_string.decode('utf-8')
|
||||
else:
|
||||
logger.warning(f"{file_path} 不是一个真实有效的文件路径")
|
||||
|
||||
@@ -22,7 +22,7 @@ class BaseRequest:
|
||||
Request操作封装
|
||||
"""
|
||||
|
||||
TIMEOUT = 5
|
||||
TIMEOUT = 8
|
||||
|
||||
session = None
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ class RequestPreDataHandle:
|
||||
"""
|
||||
|
||||
def __init__(self, request_data: dict, global_var: dict):
|
||||
logger.trace(f"\n======================================================\n" \
|
||||
logger.debug(f"\n======================================================\n" \
|
||||
"-------------Start:处理用例数据前--------------------\n"
|
||||
f"用例标题(title): {type(request_data.get('title', None))} || {request_data.get('title', None)}\n" \
|
||||
f"用例优先级(severity): {type(request_data.get('severity', None))} || {request_data.get('severity', None)}\n" \
|
||||
@@ -61,7 +61,7 @@ class RequestPreDataHandle:
|
||||
self.payload_handle()
|
||||
self.files_handle()
|
||||
self.assert_handle()
|
||||
logger.trace(f"\n======================================================\n" \
|
||||
logger.debug(f"\n======================================================\n" \
|
||||
"-------------End:处理用例数据后--------------------\n"
|
||||
f"用例标题(title): {type(self.request_data.get('title', None))} || {self.request_data.get('title', None)}\n" \
|
||||
f"用例优先级(severity): {type(self.request_data.get('severity', None))} || {self.request_data.get('severity', None)}\n" \
|
||||
|
||||
Reference in New Issue
Block a user