diff --git a/Pipfile b/Pipfile index fa7b973..e2ca3a7 100644 --- a/Pipfile +++ b/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] diff --git a/README.md b/README.md index f309b4e..8811037 100644 --- a/README.md +++ b/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,可以针对单个用例重复执行多次。 ## 九、初始化项目可能遇到的问题 diff --git a/config/settings.py b/config/settings.py index 508dde6..8f1a241 100644 --- a/config/settings.py +++ b/config/settings.py @@ -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", diff --git a/conftest.py b/conftest.py index 9f3cc42..b2ae28e 100644 --- a/conftest.py +++ b/conftest.py @@ -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: diff --git a/interface/gitlink/organization/test_delete_organization.yaml b/interface/gitlink/organization/test_delete_organization.yaml new file mode 100644 index 0000000..a0b43c3 --- /dev/null +++ b/interface/gitlink/organization/test_delete_organization.yaml @@ -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 \ No newline at end of file diff --git a/interface/gitlink/organization/test_new_organization.yaml b/interface/gitlink/organization/test_new_organization.yaml index 85ee81d..5ebdc2d 100644 --- a/interface/gitlink/organization/test_new_organization.yaml +++ b/interface/gitlink/organization/test_new_organization.yaml @@ -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: \ No newline at end of file + extract: + type_jsonpath: + org_id: $.id + case_dependence: + teardown: + interface: gitlink_projects_delete_organization_01 \ No newline at end of file diff --git a/interface/gitlink/projects/issues/__init__.py b/interface/gitlink/projects/issues/__init__.py new file mode 100644 index 0000000..d193ece --- /dev/null +++ b/interface/gitlink/projects/issues/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +# @Time : 2023/11/14 9:56 +# @Author : floraachy +# @File : __init__.py +# @Software: PyCharm +# @Desc: diff --git a/interface/gitlink/projects/issues/get_issue_detail.yaml b/interface/gitlink/projects/issues/get_issue_detail.yaml new file mode 100644 index 0000000..c52148e --- /dev/null +++ b/interface/gitlink/projects/issues/get_issue_detail.yaml @@ -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: \ No newline at end of file diff --git a/interface/gitlink/projects/issues/get_issue_journals_detail.yaml b/interface/gitlink/projects/issues/get_issue_journals_detail.yaml new file mode 100644 index 0000000..dd119e9 --- /dev/null +++ b/interface/gitlink/projects/issues/get_issue_journals_detail.yaml @@ -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: \ No newline at end of file diff --git a/interface/gitlink/projects/issues/get_issue_list.yaml b/interface/gitlink/projects/issues/get_issue_list.yaml new file mode 100644 index 0000000..ad8e25b --- /dev/null +++ b/interface/gitlink/projects/issues/get_issue_list.yaml @@ -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: \ No newline at end of file diff --git a/interface/gitlink/projects/issues/new_issue_journals.yaml b/interface/gitlink/projects/issues/new_issue_journals.yaml new file mode 100644 index 0000000..6b2e862 --- /dev/null +++ b/interface/gitlink/projects/issues/new_issue_journals.yaml @@ -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: \ No newline at end of file diff --git a/interface/gitlink/projects/issues/new_issue_journals_reply.yaml b/interface/gitlink/projects/issues/new_issue_journals_reply.yaml new file mode 100644 index 0000000..15bdc36 --- /dev/null +++ b/interface/gitlink/projects/issues/new_issue_journals_reply.yaml @@ -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: \ No newline at end of file diff --git a/interface/gitlink/projects/issues/test_new_issue.yaml b/interface/gitlink/projects/issues/test_new_issue.yaml new file mode 100644 index 0000000..8aef150 --- /dev/null +++ b/interface/gitlink/projects/issues/test_new_issue.yaml @@ -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 \ No newline at end of file diff --git a/interface/gitlink/projects/repository/test_repo_sub_entries.yaml b/interface/gitlink/projects/repository/test_repo_sub_entries.yaml index 790bafd..692cac0 100644 --- a/interface/gitlink/projects/repository/test_repo_sub_entries.yaml +++ b/interface/gitlink/projects/repository/test_repo_sub_entries.yaml @@ -25,7 +25,6 @@ case_info: payload: ref: master filepath: - type: # 可选file或者dir files: assert_response: status_code: 200 diff --git a/interface/gitlink/projects/test_upload_files.yaml b/interface/gitlink/projects/test_upload_files.yaml index cfae12f..58fa9fb 100644 --- a/interface/gitlink/projects/test_upload_files.yaml +++ b/interface/gitlink/projects/test_upload_files.yaml @@ -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 diff --git a/interface/gitlink/projects/wiki/test_new_wiki.yaml b/interface/gitlink/projects/wiki/test_new_wiki.yaml new file mode 100644 index 0000000..9400235 --- /dev/null +++ b/interface/gitlink/projects/wiki/test_new_wiki.yaml @@ -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 \ No newline at end of file diff --git a/interface/gitlink/test_login.yaml b/interface/gitlink/test_login.yaml index 8a9f074..66a0ec6 100644 --- a/interface/gitlink/test_login.yaml +++ b/interface/gitlink/test_login.yaml @@ -5,6 +5,7 @@ case_common: allure_story: 登录接口 # 故事,可以理解为场景,相当于method级的标签, 往下是 title case_markers: # pytest框架的标记 pytest.mark. - gitlink + - smoke - login: 登录接口 # 用例数据 diff --git a/pytest.ini b/pytest.ini index 0834d90..02b3f0f 100644 --- a/pytest.ini +++ b/pytest.ini @@ -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 \ No newline at end of file + test_demo: demo case + smoke:smoke \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 21ba911..c40af7e 100644 Binary files a/requirements.txt and b/requirements.txt differ diff --git a/test_case/conftest.py b/test_case/conftest.py index d56b6e2..b5493e0 100644 --- a/test_case/conftest.py +++ b/test_case/conftest.py @@ -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) \ No newline at end of file + res = api_work_flow(login_oauth_token_api, GLOBAL_VARS) + GLOBAL_VARS.update(res) \ No newline at end of file diff --git a/utils/assertion_utils/assert_control.py b/utils/assertion_utils/assert_control.py index 6665b1b..5c2e36b 100644 --- a/utils/assertion_utils/assert_control.py +++ b/utils/assertion_utils/assert_control.py @@ -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 diff --git a/utils/case_generate_utils/case_fun_generate.py b/utils/case_generate_utils/case_fun_generate.py index cbb36f6..fbe13b6 100644 --- a/utils/case_generate_utils/case_fun_generate.py +++ b/utils/case_generate_utils/case_fun_generate.py @@ -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 diff --git a/utils/data_utils/data_handle.py b/utils/data_utils/data_handle.py index 806774f..fbaf8ad 100644 --- a/utils/data_utils/data_handle.py +++ b/utils/data_utils/data_handle.py @@ -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 diff --git a/utils/data_utils/extract_data_handle.py b/utils/data_utils/extract_data_handle.py index 41c2d1e..e7c2582 100644 --- a/utils/data_utils/extract_data_handle.py +++ b/utils/data_utils/extract_data_handle.py @@ -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" diff --git a/utils/files_utils/files_handle.py b/utils/files_utils/files_handle.py index 5ee7528..77b7cc6 100644 --- a/utils/files_utils/files_handle.py +++ b/utils/files_utils/files_handle.py @@ -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} 不是一个真实有效的文件路径") diff --git a/utils/requests_utils/base_request.py b/utils/requests_utils/base_request.py index 254fb9e..1d9646d 100644 --- a/utils/requests_utils/base_request.py +++ b/utils/requests_utils/base_request.py @@ -22,7 +22,7 @@ class BaseRequest: Request操作封装 """ - TIMEOUT = 5 + TIMEOUT = 8 session = None diff --git a/utils/requests_utils/request_control.py b/utils/requests_utils/request_control.py index 9bf9ce7..1d72c32 100644 --- a/utils/requests_utils/request_control.py +++ b/utils/requests_utils/request_control.py @@ -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" \