diff --git a/README.md b/README.md index 7fa9307..b450b80 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ ## 一、框架介绍 -本框架主要是基于 Python + pytest + Allure + loguru + 邮件通知/企业微信通知/钉钉通知 实现的接口自动化框架。 +本框架主要是基于 Python + Pytest + Allure + Loguru + 邮件通知/企业微信通知/钉钉通知 实现的接口自动化框架。 * git地址: [https://www.gitlink.org.cn/floraachy/apiautotest](https://www.gitlink.org.cn/floraachy/apiautotest) * 项目参与者: floraachy @@ -193,8 +193,9 @@ case_common :公共参数 allure_feature:用作于@allure.feature()装饰器中的内容。 allure_story:用作于@allure.story()装饰器中的内容。 case_markers: 给测试方法添加标记,支持自定义标记,skip, usefixtures。 格式是列表嵌套字符串或者字典。例如: # ['glcc', {'skip': '跳过执行该用例'}] -case_001:用例ID - feature:用例所属模块, 类似于@allure.feature()。 +case_info: 具体的用例数据,是以列表的形式进行管理 +- + id:用例id title:用例标题 run:是否执行用例,为空或者True都会执行,为False则不执行。 url:请求路径(可填写全路径 或者 资源路径)。通常我们填写资源路径。在用例执行前,会针对路径进行处理。具体可见case_utils.request_data_handle.py.RequestPreDataHandle.url_handle。注:请求路径=基准路径(host/base_url)+资源路径(url)。 diff --git a/case_utils/case_data_analysis.py b/case_utils/case_data_analysis.py index 19acaaf..16100f2 100644 --- a/case_utils/case_data_analysis.py +++ b/case_utils/case_data_analysis.py @@ -22,7 +22,9 @@ class CaseDataCheck: @property def get_method(self) -> Text: - + """ + 处理method参数:校验method参数是否是指定枚举值中的一个 + """ return self.check_params_right( Method, self.case_data.get(TestCaseEnum.METHOD.value[0]) @@ -30,6 +32,9 @@ class CaseDataCheck: @property def get_severity(self) -> Text: + """ + 处理severity参数:如果Severity为空或者不传或者传错,视为NORMAL + """ # 如果Severity为空或者不传或者传错,视为NORMAL attr = self.case_data.get(TestCaseEnum.SEVERITY.value[0]) if attr is None or attr.upper() not in Severity._member_names_: @@ -39,14 +44,20 @@ class CaseDataCheck: @property def get_request_type(self): + """ + 处理request_type参数:校验request_type参数是否是指定枚举值中的一个 + """ return self.check_params_right( RequestType, self.case_data.get(TestCaseEnum.REQUEST_TYPE.value[0]) ) def check_case_data_attr(self, attr: Text): + """ + 检查用例中是否缺失某个参数 + """ assert attr in self.case_data.keys(), ( - f"用例ID为 {self.case_id} 的用例中缺少 {attr} 参数,请确认用例内容是否编写规范." + f"用例ID: {self.case_id} --> 缺少 {attr} 参数,请确认用例内容是否编写规范." ) def check_params_exit(self): @@ -54,57 +65,59 @@ class CaseDataCheck: 遍历一个枚举类中所有成员,并检查与每个成员对应的实例属性是否存在。 如果属性存在,则什么也不做,如果不存在,则抛出异常或执行其他操作 """ - for enum in list(TestCaseEnum._value2member_map_.keys()): + print(f"打印:{list(TestCaseEnum._value2member_map_)}") + for enum in list(TestCaseEnum._value2member_map_): if enum[1]: self.check_case_data_attr(enum[0]) + def check_required_fields(self): + for field in TestCaseEnum: + if field.value[1]: # 判断是否为必填参数 + field_name = field.value[0] + value = self.case_data[field_name] + if value is None or (isinstance(value, str) and len(value.strip()) == 0): + raise ValueError(f"用例ID: {self.case_id} --> {field_name}字段的值是:{value}, 该字段值是必填,请检查是否填写正确.") + def check_params_right(self, enum_name, attr): """ 检查参数值是否正确,符合要求规范 """ _member_names_ = enum_name._member_names_ assert attr.upper() in _member_names_, ( - f"用例ID为 {self.case_id} 的用例中 {enum_name}: {attr} 填写不正确," + f"用例ID: {self.case_id} --> {enum_name}: {attr} 填写不正确," f"当前框架中只支持 {_member_names_} 类型." f"如有疑问,请联系管理员." ) return attr.upper() - @property - def get_assert_response(self): - _assert_data = self.case_data.get(TestCaseEnum.ASSERT_RESPONSE.value[0]) - assert _assert_data is not None, ( - f"用例ID 为 {self.case_id} 未添加断言" - ) - return _assert_data - def case_process(self, cases): case_list = [] for key, values in cases.items(): # 公共配置中的数据,与用例数据不同,需要单独处理 - if key != 'case_common': - # 检查用例数据,去除用例数据中的空格 - for k, v in values.items(): - values[k] = v.strip() if isinstance(v, str) else v - self.case_data = values - self.case_id = key - self.check_params_exit() - case_data = { - 'feature': self.case_data.get(TestCaseEnum.FEATURE.value[0]), - 'title': self.case_data.get(TestCaseEnum.TITLE.value[0]), - 'severity': self.get_severity, - 'url': self.case_data.get(TestCaseEnum.URL.value[0]), - 'run': self.case_data.get(TestCaseEnum.RUN.value[0]), - 'method': self.get_method, - 'headers': self.case_data.get(TestCaseEnum.HEADERS.value[0]), - 'cookies': self.case_data.get(TestCaseEnum.COOKIES.value[0]), - 'request_type': self.get_request_type, - 'payload': self.case_data.get(TestCaseEnum.PAYLOAD.value[0]), - 'files': self.case_data.get(TestCaseEnum.FILES.value[0]), - 'extract': self.case_data.get(TestCaseEnum.EXTRACT.value[0]), - "assert_response": self.get_assert_response, - "assert_sql": self.case_data.get(TestCaseEnum.ASSERT_SQL.value[0]), - } - case_list.append(TestCase(**case_data).dict()) + if key == 'case_info': + for value in values: + self.case_data = value + self.case_id = value.get("id") + # 检查用例参数,需要必填的是否有值 + self.check_required_fields() + # 检查用例参数值,是否都填写正确 + self.check_params_exit() + case_data = { + 'id': self.case_data.get(TestCaseEnum.ID.value[0]), + 'title': self.case_data.get(TestCaseEnum.TITLE.value[0]), + 'severity': self.get_severity, + 'url': self.case_data.get(TestCaseEnum.URL.value[0]), + 'run': self.case_data.get(TestCaseEnum.RUN.value[0]), + 'method': self.get_method, + 'headers': self.case_data.get(TestCaseEnum.HEADERS.value[0]), + 'cookies': self.case_data.get(TestCaseEnum.COOKIES.value[0]), + 'request_type': self.get_request_type, + 'payload': self.case_data.get(TestCaseEnum.PAYLOAD.value[0]), + 'files': self.case_data.get(TestCaseEnum.FILES.value[0]), + 'extract': self.case_data.get(TestCaseEnum.EXTRACT.value[0]), + "assert_response": self.case_data.get(TestCaseEnum.ASSERT_RESPONSE.value[0]), + "assert_sql": self.case_data.get(TestCaseEnum.ASSERT_SQL.value[0]), + } + case_list.append(case_data) return case_list diff --git a/case_utils/case_fun_handle.py b/case_utils/case_fun_handle.py index 4a3747f..ca01fb5 100644 --- a/case_utils/case_fun_handle.py +++ b/case_utils/case_fun_handle.py @@ -57,8 +57,7 @@ def handle_excel_data(file): "allure_story": v["sheet_name"] } # 处理excel用例数据 - for case in v["data"]: - excel_case[case["id"]] = case + excel_case["case_info"] = v["data"] # 检查用例数据是否符合规范 tested_case = CaseDataCheck().case_process(excel_case) # 生成测试方法 diff --git a/config/models.py b/config/models.py index ad64d73..a3e4a5b 100644 --- a/config/models.py +++ b/config/models.py @@ -76,7 +76,7 @@ class TestCaseEnum(Enum): """ 测试用例中字段 """ - FEATURE = ("feature", False) + ID = ("id", True) TITLE = ("title", True) URL = ("url", True) SEVERITY = ("severity", False) @@ -96,7 +96,7 @@ class TestCase(BaseModel): """ 测试用例各数据格式要求 """ - feature: Union[None, Text] = None + id: Union[None, Text] title: Text severity: Text url: Text diff --git a/config/settings.py b/config/settings.py index 7a903b2..c53c22f 100644 --- a/config/settings.py +++ b/config/settings.py @@ -8,7 +8,7 @@ # ------------------------------------ 配置信息 ----------------------------------------------------# # 0代表执行Excel和yaml两种格式的用例, 1 代表 yaml文件,2 用例代表Excel用例, 其他数值将不自动生成用例,仅能执行手动编写的用例 -CASE_FILE_TYPE = 1 +CASE_FILE_TYPE = 0 # 0表示默认不发送任何通知, 1代表钉钉通知,2代表企业微信通知, 3代表邮件通知, 4代表所有途径都发送通知 SEND_RESULT_TYPE = 0 diff --git a/data/gitlink/glcc/test_get_apply_information.yml b/data/gitlink/glcc/test_get_apply_information.yml index eaa998b..dd83f56 100644 --- a/data/gitlink/glcc/test_get_apply_information.yml +++ b/data/gitlink/glcc/test_get_apply_information.yml @@ -7,8 +7,9 @@ case_common: - get_project - skip: 跳过执行该用例 -case_glcc_demo_01: - feature: GLCC +case_info: +- + id: case_glcc_demo_01 title: 获取已报名成功的项目数据 severity: normal run: True @@ -26,8 +27,8 @@ case_glcc_demo_01: $.message: success assert_sql: -case_glcc_demo_02: - feature: GLCC +- + id: case_glcc_demo_02 title: 获取已报名成功的课题数据 severity: normal run: True diff --git a/data/gitlink/login_demo.yaml b/data/gitlink/login_demo.yaml index 1cbb735..cd00900 100644 --- a/data/gitlink/login_demo.yaml +++ b/data/gitlink/login_demo.yaml @@ -9,8 +9,9 @@ case_common: - skip: 跳过执行该用例 # 用例数据 -case_login_demo_01: - feature: 登录 +case_info: +- + id: case_login_01 title: 用户名密码正确,登录成功(不校验数据库) run: True severity: normal @@ -39,8 +40,8 @@ case_login_demo_01: $.user_id: 85390 assert_sql: -case_login_demo_02: - feature: 登录 +- + id: case_login_02 title: 用户名密码正确,登录成功(校验数据库) run: False severity: minor @@ -71,8 +72,9 @@ case_login_demo_02: eq: sql: select count(*) from tokens where user_id=${user_id}; len: 1 -case_login_demo_03: - feature: 登录 + +- + id: case_login_03 title: 用户名正确,密码错误,登录失败 severity: critical run: False diff --git a/data/gitlink/test_gitlink_demo.xlsx b/data/gitlink/test_gitlink_demo.xlsx index 1ce5296..3ce608f 100644 Binary files a/data/gitlink/test_gitlink_demo.xlsx and b/data/gitlink/test_gitlink_demo.xlsx differ diff --git a/data/gitlink/test_new_project_demo.yaml b/data/gitlink/test_new_project_demo.yaml index 0a6c953..c03bcef 100644 --- a/data/gitlink/test_new_project_demo.yaml +++ b/data/gitlink/test_new_project_demo.yaml @@ -9,8 +9,9 @@ case_common: - usefixtures: login_init # 用例数据 -case_new_project_demo_01: - feature: 新建项目 +case_info: +- + id: case_new_project_01 title: 正确输入各项必填参数,新建项目成功(不校验数据库, header里面传cookies) severity: critical run: True @@ -36,8 +37,8 @@ case_new_project_demo_01: $.login: ${login} assert_sql: -case_new_project_demo_02: - feature: 新建项目 +- + id: case_new_project_02 title: 正确输入各项必填参数,新建项目成功(不校验数据库,单独传cookies) run: True url: /api/projects.json @@ -61,8 +62,8 @@ case_new_project_demo_02: $.login: ${login} assert_sql: -case_new_project_demo_03: - feature: 新建项目 +- + id: case_new_project_03 title: 正确输入各项必填参数,新建项目成功(校验数据库) severity: normal run: False @@ -91,8 +92,8 @@ case_new_project_demo_03: $.name: ${project_name} $.identifier: ${project_identifier} -case_new_project_demo_04: - feature: 新建项目 +- + id: case_new_project_04 title: 正确输入各项必填参数,新建项目成功(04) severity: normal run: False @@ -117,8 +118,8 @@ case_new_project_demo_04: $.login: ${login} assert_sql: -case_new_project_demo_05: - feature: 新建项目 +- + id: case_new_project_05 title: 正确输入各项必填参数,新建项目成功(05) severity: normal run: False diff --git a/data/gitlink/test_upload_files.yaml b/data/gitlink/test_upload_files.yaml index e766f87..3c5d343 100644 --- a/data/gitlink/test_upload_files.yaml +++ b/data/gitlink/test_upload_files.yaml @@ -9,8 +9,9 @@ case_common: - skip: 跳过该用例 # 用例数据 -case_upload_demo_01: - feature: 上传文件 +case_info: +- + id: case_upload_file_01 title: 测试单文件上传 severity: run: False @@ -30,8 +31,8 @@ case_upload_demo_01: http_code: 200 assert_sql: -case_upload_demo_02: - feature: 上传文件 +- + id: case_upload_file_02 title: 测试多文件上传(该接口不支持多文件上传,这是一个示例) severity: normal run: False diff --git a/data/test_demo.yaml b/data/test_demo.yaml index 642696f..8a8be21 100644 --- a/data/test_demo.yaml +++ b/data/test_demo.yaml @@ -6,8 +6,9 @@ case_common: case_markers: # 用例数据 -case_demo_01: - feature: debug +case_info: +- + id: case_demo_01 title: 这是一条用于调试功能的用例 run: True severity: normal diff --git a/test_case/test_manual_case/test_login_demo.py b/test_case/test_manual_case/test_login_demo.py index a9b1557..ee7a50f 100644 --- a/test_case/test_manual_case/test_login_demo.py +++ b/test_case/test_manual_case/test_login_demo.py @@ -24,10 +24,7 @@ from case_utils.allure_handle import allure_title # 读取用例数据 yaml_data = YamlHandle(filename=os.path.join(DATA_DIR, "gitlink", "login_demo.yaml")).read_yaml case_common = yaml_data["case_common"] -cases = [] -for k, v in yaml_data.items(): - if k != "case_common": - cases.append(v) +cases = yaml_data["case_info"] @allure.epic(case_common["allure_epic"])