修改用例格式由字典改为列表,并增加用例字段必填校验

This commit is contained in:
floraachy
2023-08-15 14:22:37 +08:00
parent c19193bcc6
commit 0a881116a3
12 changed files with 90 additions and 74 deletions
+4 -3
View File
@@ -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)。
+34 -21
View File
@@ -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,43 +65,45 @@ 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
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 = {
'feature': self.case_data.get(TestCaseEnum.FEATURE.value[0]),
'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]),
@@ -102,9 +115,9 @@ class CaseDataCheck:
'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_response": self.case_data.get(TestCaseEnum.ASSERT_RESPONSE.value[0]),
"assert_sql": self.case_data.get(TestCaseEnum.ASSERT_SQL.value[0]),
}
case_list.append(TestCase(**case_data).dict())
case_list.append(case_data)
return case_list
+1 -2
View File
@@ -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)
# 生成测试方法
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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
@@ -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
+8 -6
View File
@@ -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
Binary file not shown.
+11 -10
View File
@@ -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
+5 -4
View File
@@ -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
+3 -2
View File
@@ -6,8 +6,9 @@ case_common:
case_markers:
# 用例数据
case_demo_01:
feature: debug
case_info:
-
id: case_demo_01
title: 这是一条用于调试功能的用例
run: True
severity: normal
@@ -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"])