增加接口请求后的等待时间,方便接口调用后,进行一系列数据初始化操作,待操作成功后,执行后续接口

This commit is contained in:
floraachy
2024-04-12 13:45:22 +08:00
parent 98a2994ad7
commit fd9e5b8df1
6 changed files with 48 additions and 19 deletions

View File

@@ -3,7 +3,7 @@
公司突然要求你做自动化,但是没有代码基础不知道怎么做?或者有自动化基础,但是不知道如何系统性的做自动化, 放在yaml文件中维护不知道如何处理多业务依赖的逻辑
那么本自动化框架,将为你解决这些问题。
- 框架主要使用 python 语言编写,结合 pytest 进行二次开发,用户仅需要在 yaml 或者 excel 文件中编写测试用例, 编写成功之后,会自动生成测试用例代码,零基础代码小白,也可以操作
- 框架主要使用 python 语言编写,结合 pytest 进行二次开发,用户仅需要在 yaml 文件中编写测试用例, 编写成功之后,会自动生成测试用例代码。
- 如果是具备代码基础的,也可以直接通过 py 文件编写测试用例。
- 使用 Allure 生成报告,并针对测试报告样式进行了调整,使得报告更加美观;
- 测试完成后,支持发送 企业微信通知/ 钉钉通知/ 邮箱通知,灵活配置。
@@ -30,7 +30,7 @@
* 支持单独调试用例,支持用例的重复执行
* 框架天然支持接口动态传参、关联灵活处理
* 支持测试数据分析,测试数据不符合规范有预警机制
* 支持通过用例数据动态配置pytest.mark 包括自定义标记pytest.mark.skip以及pytest,mark.usefixtures
* 支持通过用例数据动态配置pytest.mark 包括自定义标记pytest.mark.skip以及pytest.mark.usefixtures
* 支持利用allure设置用例优先级运行指定优先级的用例
* 执行环境一键切换,解决多环境相互影响问题
* 自动生成用例代码: 测试人员在yaml/excel文件中填写好测试用例, 程序可以直接生成用例代码,纯小白也能使用
@@ -40,6 +40,7 @@
* 钉钉、企业微信通知: 支持多种通知场景,执行成功之后,可选择发送钉钉、或者企业微信、邮箱通知
* 使用pipenv管理虚拟环境和依赖文件提供了一系列命令和选项来帮助你实现各种依赖和环境管理相关的操作
* 支持将swagger.json接口文档转为YAML用例
* 支持接口相应后添加等待时间,方便接口调用后,进行一系列数据初始化操作,待操作成功后,执行后续接口
@@ -48,7 +49,6 @@
allure-pytest = "==2.9.45"
click = "==8.1.7"
faker = "==21.0.0"
jsonpath = "==0.82.2"
loguru = "==0.7.2"
openpyxl = "==3.1.2"
pydantic = "==2.5.2"
@@ -60,7 +60,8 @@ requests-toolbelt = "==1.0.0"
sshtunnel = "==0.4.0"
xpinyin = "==0.7.6"
yagmail = "==0.15.293"
pytest-repeat = "*"
pytest-repeat = "==0.9.3"
jsonpath = "*"
```
@@ -163,6 +164,7 @@ case_info: # 具体的用例数据,是以列表的形式进行管理
request_type: 请求数据类型params, json, file, data
payload: 请求参数
files: 需要上传的文件的相对路径会自动拼接files目录。 os.path.join(files, "这里传递的files参数值")
wait_seconds: 选填,接口请求后的等待时间,单位是秒。传递错误,会被认为是空
assert_response: 响应断言
assert_sql: 数据库断言
extract: 后置提取参数

View File

@@ -4,9 +4,11 @@ case_common:
allure_story: 开通/关闭工作台
case_markers:
- pms
- ok
- usefixtures: gitlink_login
# 前提条件当前存在gitlink组织组织已开通工作台
# (开通工作台后,需要等待一定时间,才能删除工作台成功)
case_info:
-
@@ -43,13 +45,14 @@ case_info:
# 开通组织工作台
- pms_open_enterprise_01
teardown:
# 删除组织
- gitlink_delete_organization_01
interface:
# 删除组织
- gitlink_delete_organization_01
-
id: pms_close_enterprise_02
title: 密码错误关闭工作台,关闭失败
run: True
run: true
severity: normal
url: ${pms_host}/api/pms/pmsEnterprise/${org_identifier}
method: DELETE
@@ -58,28 +61,28 @@ case_info:
cookies: ${cookies}
request_type: params
payload:
password: ${env_password}
password: 1111111222
files:
assert_response:
status_code: 200
assertMessage:
type_jsonpath: $.msg
expect_value: 操作成功
expect_value: 密码错误
assert_type: ==
assertCode:
type_jsonpath: $.code
expect_value: 200
expect_value: 500
assert_type: ==
assert_sql:
extract:
case_dependence:
setup:
interface:
# 新建组织获取组织id
- gitlink_new_organization_01
# 开通组织工作台
- pms_open_enterprise_01
teardown:
setup:
interface:
# 新建组织获取组织id
- gitlink_new_organization_01
# 开通组织工作台
- pms_open_enterprise_01
teardown:
interface:
# 删除组织
- gitlink_delete_organization_01
- gitlink_delete_organization_01

View File

@@ -5,6 +5,7 @@ case_common:
case_markers:
- pms
- debug
- ok
- usefixtures: gitlink_login
# 前提条件当前存在gitlink组织组织未开通工作台
@@ -33,6 +34,7 @@ case_info:
userId: ${env_user_id}
roleKey: pms_org_admin
files:
wait_seconds: 6
assert_response:
status_code: 200
assertMessage:

View File

@@ -113,6 +113,7 @@ class CaseDataCheck:
'request_type': self.get_request_type,
'payload': self.case_data.get(TestCaseEnum.PAYLOAD.value[0]),
'files': self.case_data.get(TestCaseEnum.FILES.value[0]),
"wait_seconds": self.case_data.get(TestCaseEnum.WAIT_SECONDS.value[0]),
"assert_response": self.case_data.get(TestCaseEnum.ASSERT_RESPONSE.value[0]),
"assert_sql": self.case_data.get(TestCaseEnum.ASSERT_SQL.value[0]),
'extract': self.case_data.get(TestCaseEnum.EXTRACT.value[0]),

View File

@@ -87,6 +87,7 @@ class TestCaseEnum(Enum):
REQUEST_TYPE = ("request_type", True)
PAYLOAD = ("payload", False)
FILES = ("files", False)
WAIT_SECONDS = ("wait_seconds", False)
EXTRACT = ("extract", False)
ASSERT_RESPONSE = ("assert_response", True)
ASSERT_SQL = ("assert_sql", False)
@@ -108,6 +109,7 @@ class TestCase(BaseModel):
run: Union[None, bool, Text] = None
payload: Any = None
files: Any = None
wait_seconds: int = None
extract: Union[None, Dict, Text] = None
assert_response: Union[None, Dict, Text]
assert_sql: Union[None, Dict, Text] = None

View File

@@ -11,6 +11,7 @@ import json
import os
import http.cookiejar
import copy
import time
# 第三方库导入
from requests import Response
from loguru import logger
@@ -42,6 +43,7 @@ class RequestPreDataHandle:
f"请求类型(request_type): {type(request_data.get('request_type', None))} || {request_data.get('request_type', None)}\n" \
f"请求参数(payload): {type(request_data.get('payload', None))} || {request_data.get('payload', None)}\n" \
f"请求文件(files): {type(request_data.get('files', None))} || {request_data.get('files', None)}\n" \
f"请求后等待(wait_seconds): {type(request_data.get('wait_seconds', None))} || {request_data.get('wait_seconds', None)}\n" \
f"响应断言(assert_response): {type(request_data.get('assert_response', None))} || {request_data.get('assert_response', None)}\n" \
f"数据库断言(assert_sql): {type(request_data.get('assert_sql', None))} || {request_data.get('assert_sql', None)}\n" \
f"后置提取参数(extract): {type(request_data.get('extract', None))} || {request_data.get('extract', None)}\n" \
@@ -60,6 +62,7 @@ class RequestPreDataHandle:
self.cookies_handle()
self.payload_handle()
self.files_handle()
self.wait_seconds_handle()
self.assert_handle()
self.extract_handle()
logger.debug(f"\n======================================================\n" \
@@ -73,6 +76,7 @@ class RequestPreDataHandle:
f"请求类型(request_type): {type(self.request_data.get('request_type', None))} || {self.request_data.get('request_type', None)}\n" \
f"请求参数(payload): {type(self.request_data.get('payload', None))} || {self.request_data.get('payload', None)}\n" \
f"请求文件(files): {type(self.request_data.get('files', None))} || {self.request_data.get('files', None)}\n" \
f"请求后等待(wait_seconds): {type(self.request_data.get('wait_seconds', None))} || {self.request_data.get('wait_seconds', None)}\n" \
f"响应断言(assert_response): {type(self.request_data.get('assert_response', None))} || {self.request_data.get('assert_response', None)}\n" \
f"数据库断言(assert_sql): {type(self.request_data.get('assert_sql', None))} || {self.request_data.get('assert_sql', None)}\n" \
f"后置提取参数(extract): {type(self.request_data.get('extract', None))} || {self.request_data.get('extract', None)}\n" \
@@ -170,6 +174,15 @@ class RequestPreDataHandle:
# 将文件处理成绝对路径
self.request_data["files"] = os.path.join(FILES_DIR, files)
def wait_seconds_handle(self):
"""
处理等待时间参数如果不能转为int类型则认为是none
"""
wait_seconds = self.request_data.get("wait_seconds", None)
try:
self.request_data["wait_seconds"] = int(wait_seconds)
except:
self.request_data["wait_seconds"] = None
def assert_handle(self):
# 处理响应断言参数
assert_response = self.request_data.get("assert_response", None)
@@ -208,6 +221,7 @@ class RequestHandle:
request_type = kwargs.get("request_type")
payload = kwargs.get("payload")
files = kwargs.get("files")
wait_seconds = kwargs.get("wait_seconds")
status_code = kwargs.get("status_code")
response_result = kwargs.get("response_result")
response_time_seconds = kwargs.get("response_time_seconds")
@@ -238,6 +252,7 @@ class RequestHandle:
allure_step(f"请求关键字: {request_type}")
allure_step(f"请求参数: {payload}")
allure_step(f"请求文件: {files}")
allure_step(f"请求后等待时间: {wait_seconds}")
allure_step(f"响应码: {status_code}")
allure_step(f"响应结果: {response_result}")
allure_step(f"响应耗时: {response_time_seconds} s || {response_time_millisecond} ms")
@@ -247,7 +262,11 @@ class RequestHandle:
发送请求并进行后置参数提取操作
"""
response = BaseRequest.send_request(self.case_data)
# 根据配置,增加接口请求等待时间。适应部分调用调用后,需要进行内置数据处理的问题
logger.debug(f"开始等待")
if self.case_data["wait_seconds"]:
time.sleep(self.case_data["wait_seconds"])
logger.debug(f"结束等待")
self.case_data["status_code"] = response.status_code
self.case_data["response_time_seconds"] = round(response.elapsed.total_seconds(), 2)
self.case_data["response_time_millisecond"] = round(response.elapsed.total_seconds() * 1000, 2)