修改用例格式由字典改为列表,并增加用例字段必填校验
This commit is contained in:
@@ -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)。
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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.
@@ -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
|
||||
|
||||
@@ -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
@@ -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"])
|
||||
|
||||
Reference in New Issue
Block a user