feat: 添加JoyHub运费模板和Banner管理接口用例

This commit is contained in:
2026-05-06 10:54:03 +08:00
parent cc6733a8fb
commit 86f4e8288e
89 changed files with 11557 additions and 3 deletions

View File

@@ -0,0 +1,292 @@
import pytest
import allure
import logging
import requests
import json
import time
from dulizhan.library.BusinessKw.JoyHub.BannerManage import BannerManage
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
@allure.feature("管理后台 - Banner管理模块")
class TestBannerManage:
banner_id = None
token_set = False
@classmethod
def setup_class(cls):
"""在整个测试类开始时登录一次所有测试用例共享token"""
logging.info("=============================================")
logging.info("=========== 开始登录获取Token ============")
logging.info("=============================================")
cls.test_case = BannerManage()
username = "joytest"
password = "Zhou1599"
cls.test_case._clear_user_fingerprint(username)
url = "https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev"
payload = {"username": username, "password": password}
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
try:
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
login_response = response.json()
if login_response and login_response.get('code') == 0:
token = login_response.get('data', {}).get('accessToken', '')
if token:
cls.test_case.set_joyhub_token(token)
cls.token_set = True
logging.info("登录成功获取到Token: {}...".format(token[:20]))
else:
logging.warning("登录成功但未获取到Token")
else:
logging.error("登录失败: {}".format(login_response))
except Exception as e:
logging.error("登录异常: {}".format(str(e)))
@allure.story("验证登录")
@allure.title("测试登录接口")
def test_joyhub_login_post(self):
"""测试登录接口"""
assert self.token_set is True, "登录失败Token未设置"
logging.info("登录验证通过Token已设置")
@allure.story("验证获得Banner分页")
@allure.title("测试获得Banner管理分页接口")
def test_joyhub_banner_page_get(self):
"""测试获得Banner管理分页接口"""
with allure.step("1. 准备请求参数"):
params = {
"page_no": 1,
"page_size": 10,
"position": "",
"title": "",
"platform": "",
"lang": "",
"banner_type": "",
"status": ""
}
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用接口"):
resp = self.test_case.kw_joyhub_banner_page_get(**params)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert "list" in resp["data"], "响应中缺少list字段"
assert "total" in resp["data"], "响应中缺少total字段"
assert isinstance(resp["data"]["list"], list), "list字段不是列表类型"
assert isinstance(resp["data"]["total"], int), "total字段不是整数类型"
logging.info("获得Banner分页列表验证通过")
@allure.story("验证创建Banner")
@allure.title("测试创建Banner管理接口")
def test_joyhub_banner_create_post(self):
"""测试创建Banner管理接口"""
with allure.step("1. 准备请求参数"):
timestamp = int(time.time())
params = {
"position": f"home_{timestamp}",
"platform": 1,
"lang": "en",
"rank_num": timestamp % 1000,
"banner_type": "promotion",
"status": 1,
"interval_time": 5,
"title": f"测试Banner_{timestamp}",
"sub_title": "测试副标题",
"image": {'url': 'https://www.toendi.com/static/image/cd94c191561c4a37a04c78fca2913851.webp', 'name': 'Test Banner', 'mime_type': 'image/webp'},
"link": "https://example.com"
}
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用接口"):
resp = self.test_case.kw_joyhub_banner_create_post(**params)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert isinstance(resp["data"], int), "data字段不是整数类型"
TestBannerManage.banner_id = resp["data"]
logging.info(f"创建Banner成功Banner ID: {TestBannerManage.banner_id}")
@allure.story("验证获得Banner详情")
@allure.title("测试获得Banner详情接口")
def test_joyhub_banner_get_get(self):
"""测试获得Banner详情接口"""
with allure.step("1. 先创建一个Banner"):
timestamp = int(time.time())
create_resp = self.test_case.kw_joyhub_banner_create_post(
position=f"detail_test_{timestamp}",
platform=1,
lang="en",
rank_num=timestamp % 1000,
banner_type="promotion",
status=1,
interval_time=5,
title=f"详情测试Banner_{timestamp}"
)
banner_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None
if not banner_id:
pytest.skip("创建测试Banner失败跳过详情测试")
allure.attach(json.dumps({"id": banner_id}, ensure_ascii=False), name="Banner ID", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用获得详情接口"):
resp = self.test_case.kw_joyhub_banner_get_get(banner_id=banner_id)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert isinstance(resp["data"], dict), "data字段不是字典类型"
assert "id" in resp["data"], "响应中缺少id字段"
assert resp["data"]["id"] == banner_id, "返回的ID与请求的不一致"
logging.info("获得Banner详情验证通过")
@allure.story("验证更新Banner")
@allure.title("测试更新Banner管理接口")
def test_joyhub_banner_update_put(self):
"""测试更新Banner管理接口"""
with allure.step("1. 先创建一个Banner"):
timestamp = int(time.time())
create_resp = self.test_case.kw_joyhub_banner_create_post(
position=f"update_test_{timestamp}",
platform=1,
lang="en",
rank_num=timestamp % 1000,
banner_type="promotion",
status=1,
interval_time=5,
title=f"待更新Banner_{timestamp}"
)
banner_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None
if not banner_id:
pytest.skip("创建测试Banner失败跳过更新测试")
allure.attach(json.dumps({"id": banner_id}, ensure_ascii=False), name="Banner ID", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用更新接口"):
timestamp = int(time.time())
update_params = {
"banner_id": banner_id,
"position": f"updated_position_{timestamp}",
"platform": 2,
"lang": "de",
"rank_num": (timestamp % 1000) + 1,
"banner_type": "updated_type",
"status": 2,
"interval_time": 10,
"title": f"已更新Banner_{timestamp}",
"sub_title": "已更新副标题",
"image": {'url': 'https://www.toendi.com/static/image/updated.webp', 'name': 'Updated Banner', 'mime_type': 'image/webp'},
"link": "https://updated-example.com"
}
resp = self.test_case.kw_joyhub_banner_update_put(**update_params)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert resp["data"] is True, "更新Banner失败"
logging.info("更新Banner验证通过")
@allure.story("验证删除Banner")
@allure.title("测试删除Banner管理接口")
def test_joyhub_banner_delete_delete(self):
"""测试删除Banner管理接口"""
with allure.step("1. 先创建一个测试Banner"):
timestamp = int(time.time())
create_resp = self.test_case.kw_joyhub_banner_create_post(
position=f"delete_test_{timestamp}",
platform=1,
lang="en",
rank_num=timestamp % 1000,
banner_type="promotion",
status=2,
interval_time=5,
title=f"待删除Banner_{timestamp}"
)
banner_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None
if not banner_id:
pytest.skip("创建测试Banner失败跳过删除测试")
allure.attach(json.dumps({"id": banner_id}, ensure_ascii=False), name="待删除Banner ID", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用删除接口"):
resp = self.test_case.kw_joyhub_banner_delete_delete(banner_id=banner_id)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert resp["data"] is True, "删除Banner失败"
logging.info("删除Banner验证通过")
@allure.story("验证批量删除Banner")
@allure.title("测试批量删除Banner管理接口")
def test_joyhub_banner_delete_list_delete(self):
"""测试批量删除Banner管理接口"""
with allure.step("1. 先创建两个测试Banner"):
timestamp = int(time.time())
resp1 = self.test_case.kw_joyhub_banner_create_post(
position=f"batch_delete_1_{timestamp}",
platform=1,
lang="en",
rank_num=timestamp % 1000,
banner_type="promotion",
status=2,
interval_time=5,
title=f"批量删除Banner1_{timestamp}"
)
resp2 = self.test_case.kw_joyhub_banner_create_post(
position=f"batch_delete_2_{timestamp}",
platform=1,
lang="en",
rank_num=timestamp % 1000 + 1,
banner_type="promotion",
status=2,
interval_time=5,
title=f"批量删除Banner2_{timestamp}"
)
banner_id1 = resp1.get("data") if resp1 and resp1.get("code") == 0 else None
banner_id2 = resp2.get("data") if resp2 and resp2.get("code") == 0 else None
if not banner_id1 or not banner_id2:
pytest.skip("创建测试Banner失败跳过批量删除测试")
banner_ids = [banner_id1, banner_id2]
allure.attach(json.dumps({"ids": banner_ids}, ensure_ascii=False), name="待删除Banner IDs", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用批量删除接口"):
resp = self.test_case.kw_joyhub_banner_delete_list_delete(banner_ids=banner_ids)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert resp["data"] is True, "批量删除Banner失败"
logging.info("批量删除Banner验证通过")

View File

@@ -0,0 +1,260 @@
import pytest
import allure
import logging
import requests
import json
import time
from dulizhan.library.BusinessKw.JoyHub.DeptManage import DeptManage
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
@allure.feature("管理后台 - 部门管理模块")
class TestDeptManage:
token_set = False
dept_id = None
@classmethod
def setup_class(cls):
"""在整个测试类开始时登录一次所有测试用例共享token"""
logging.info("=============================================")
logging.info("=========== 开始登录获取Token ============")
logging.info("=============================================")
cls.test_case = DeptManage()
username = "joytest"
password = "Zhou1599"
cls.test_case._clear_user_fingerprint(username)
url = "https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev"
payload = {"username": username, "password": password}
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
try:
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
login_response = response.json()
if login_response and login_response.get('code') == 0:
token = login_response.get('data', {}).get('accessToken', '')
if token:
cls.test_case.set_joyhub_token(token)
cls.token_set = True
logging.info("登录成功获取到Token: {}...".format(token[:20]))
else:
logging.warning("登录成功但未获取到Token")
else:
logging.error("登录失败: {}".format(login_response))
logging.warning("如果是指纹锁问题,请联系管理员解除设备限制")
except Exception as e:
logging.error("登录异常: {}".format(str(e)))
def setup_method(self):
"""每个测试方法执行前检查token"""
if not self.token_set:
pytest.skip("Token未设置跳过测试")
@allure.story("验证登录接口")
@allure.title("测试登录接口")
def test_joyhub_login_post(self):
"""测试登录接口"""
assert self.token_set, "登录失败"
logging.info("登录接口验证通过")
@allure.story("验证获取部门列表")
@allure.title("测试获取部门列表接口")
def test_joyhub_dept_list_get(self):
"""测试获取部门列表接口"""
with allure.step("1. 调用接口"):
resp = self.test_case.kw_joyhub_dept_list_get()
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("2. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert isinstance(resp["data"], list), "data字段应为列表类型"
logging.info("获取部门列表接口验证通过")
@allure.story("验证创建部门")
@allure.title("测试创建部门接口")
def test_joyhub_dept_create_post(self):
"""测试创建部门接口"""
with allure.step("1. 准备请求参数"):
timestamp = int(time.time())
params = {
"name": f"测试部门_{timestamp}",
"code": f"test_dept_{timestamp}",
"sort": timestamp,
"status": 1,
"phone": "13900139000",
"email": f"test_dept_{timestamp}@example.com"
}
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用接口"):
resp = self.test_case.kw_joyhub_dept_create_post(**params)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert isinstance(resp["data"], int), "data字段应为整数类型部门ID"
TestDeptManage.dept_id = resp["data"]
logging.info(f"创建部门接口验证通过部门ID: {TestDeptManage.dept_id}")
@allure.story("验证获得部门信息")
@allure.title("测试获得部门信息接口")
def test_joyhub_dept_get_get(self):
"""测试获得部门信息接口"""
if not TestDeptManage.dept_id:
pytest.skip("没有可用的部门ID跳过测试")
with allure.step("1. 调用接口"):
resp = self.test_case.kw_joyhub_dept_get_get(dept_id=TestDeptManage.dept_id)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("2. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert "id" in resp["data"], "响应中缺少id字段"
assert resp["data"]["id"] == TestDeptManage.dept_id, "返回的部门ID与请求不一致"
logging.info("获得部门信息接口验证通过")
@allure.story("验证更新部门")
@allure.title("测试更新部门接口")
def test_joyhub_dept_update_put(self):
"""测试更新部门接口"""
if not TestDeptManage.dept_id:
pytest.skip("没有可用的部门ID跳过测试")
with allure.step("1. 准备更新参数"):
timestamp = int(time.time())
params = {
"dept_id": TestDeptManage.dept_id,
"name": f"测试部门_修改_{timestamp}",
"sort": timestamp,
"status": 1,
"phone": "13900139999",
"email": f"test_dept_updated_{timestamp}@example.com"
}
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用接口"):
resp = self.test_case.kw_joyhub_dept_update_put(**params)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert resp["data"] is True, "更新部门失败"
logging.info("更新部门接口验证通过")
@allure.story("验证删除部门")
@allure.title("测试删除部门接口")
def test_joyhub_dept_delete_post(self):
"""测试删除部门接口"""
with allure.step("1. 先创建一个测试部门"):
timestamp = int(time.time())
create_resp = self.test_case.kw_joyhub_dept_create_post(
name=f"删除测试部门_{timestamp}",
sort=999,
status=1
)
dept_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None
if not dept_id:
pytest.skip("创建测试部门失败,跳过删除测试")
allure.attach(json.dumps({"id": dept_id}, ensure_ascii=False), name="待删除部门ID", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用删除接口"):
resp = self.test_case.kw_joyhub_dept_delete_post(dept_id=dept_id)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
if resp["code"] == 1002005004:
logging.warning(f"部门已被引用无法删除code={resp.get('code')}msg={resp.get('msg')}")
pytest.skip("部门已被其他数据引用,跳过删除测试")
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert resp["data"] is True, "删除部门失败"
logging.info("删除部门接口验证通过")
@allure.story("验证批量删除部门")
@allure.title("测试批量删除部门接口")
def test_joyhub_dept_delete_list_post(self):
"""测试批量删除部门接口"""
with allure.step("1. 先创建两个测试部门"):
timestamp = int(time.time())
dept_ids = []
for i in range(2):
create_resp = self.test_case.kw_joyhub_dept_create_post(
name=f"批量删除测试部门_{timestamp}_{i}",
sort=888 + i,
status=1
)
if create_resp and create_resp.get("code") == 0:
dept_ids.append(create_resp.get("data"))
if len(dept_ids) < 2:
pytest.skip("创建测试部门失败,跳过批量删除测试")
allure.attach(json.dumps({"ids": dept_ids}, ensure_ascii=False), name="待删除部门ID列表", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用批量删除接口"):
resp = self.test_case.kw_joyhub_dept_delete_list_post(ids=dept_ids)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
if resp["code"] == 1002005004:
logging.warning(f"部门已被引用无法删除code={resp.get('code')}msg={resp.get('msg')}")
pytest.skip("部门已被其他数据引用,跳过批量删除测试")
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert resp["data"] is True, "批量删除部门失败"
logging.info("批量删除部门接口验证通过")
@allure.story("验证获取部门精简信息列表")
@allure.title("测试获取部门精简信息列表接口")
def test_joyhub_dept_list_all_simple_get(self):
"""测试获取部门精简信息列表接口"""
with allure.step("1. 调用接口"):
resp = self.test_case.kw_joyhub_dept_list_all_simple_get()
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("2. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert isinstance(resp["data"], list), "data字段应为列表类型"
logging.info("获取部门精简信息列表接口验证通过")
@allure.story("验证获取部门精简信息列表(simple-list)")
@allure.title("测试获取部门精简信息列表接口(simple-list)")
def test_joyhub_dept_simple_list_get(self):
"""测试获取部门精简信息列表接口(simple-list)"""
with allure.step("1. 调用接口"):
resp = self.test_case.kw_joyhub_dept_simple_list_get()
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("2. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert isinstance(resp["data"], list), "data字段应为列表类型"
logging.info("获取部门精简信息列表(simple-list)接口验证通过")

View File

@@ -0,0 +1,305 @@
import pytest
import allure
import logging
import requests
import json
import time
from dulizhan.library.BusinessKw.JoyHub.PostManage import PostManage
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
@allure.feature("管理后台 - 岗位模块")
class TestPostManage:
post_id = None
token_set = False
@classmethod
def setup_class(cls):
"""在整个测试类开始时登录一次所有测试用例共享token"""
logging.info("=============================================")
logging.info("=========== 开始登录获取Token ============")
logging.info("=============================================")
cls.test_case = PostManage()
username = "joytest"
password = "Zhou1599"
cls.test_case._clear_user_fingerprint(username)
url = "https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev"
payload = {"username": username, "password": password}
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
try:
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
login_response = response.json()
if login_response and login_response.get('code') == 0:
token = login_response.get('data', {}).get('accessToken', '')
if token:
cls.test_case.set_joyhub_token(token)
cls.token_set = True
logging.info("登录成功获取到Token: {}...".format(token[:20]))
else:
logging.warning("登录成功但未获取到Token")
else:
logging.error("登录失败: {}".format(login_response))
except Exception as e:
logging.error("登录异常: {}".format(str(e)))
def setup_method(self):
"""每个测试方法执行前检查token"""
if not self.token_set:
pytest.skip("Token未设置跳过测试")
@allure.story("验证登录接口")
@allure.title("测试登录接口")
def test_joyhub_login_post(self):
"""登录测试用例,验证登录接口是否正常"""
with allure.step("1. 准备登录参数"):
username = "joytest"
password = "Zhou1599"
allure.attach(f"用户名: {username}, 密码: {password}", name="登录参数", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用登录接口"):
url = "https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev"
payload = {"username": username, "password": password}
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
resp = response.json()
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="登录响应", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"登录失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert "accessToken" in resp["data"], "响应中缺少accessToken字段"
logging.info("登录接口验证通过")
@allure.story("验证获得岗位分页列表")
@allure.title("测试获得岗位分页列表接口")
def test_joyhub_post_page_get(self):
"""测试获得岗位分页列表接口"""
with allure.step("1. 准备请求参数"):
params = {"pageNo": 1, "pageSize": 10}
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用接口"):
resp = self.test_case.kw_joyhub_post_page_get(**params)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert "list" in resp["data"], "响应中缺少list字段"
assert isinstance(resp["data"]["list"], list), "list字段不是数组类型"
logging.info("获得岗位分页列表接口验证通过")
@allure.story("验证创建岗位")
@allure.title("测试创建岗位接口")
def test_joyhub_post_create_post(self):
"""测试创建岗位接口"""
with allure.step("1. 准备请求参数"):
timestamp = int(time.time())
params = {
"name": f"测试岗位_{timestamp}",
"code": f"test_post_{timestamp}",
"sort": timestamp,
"status": 1,
"remark": "测试岗位备注"
}
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用接口"):
resp = self.test_case.kw_joyhub_post_create_post(**params)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert isinstance(resp["data"], int), "data字段不是整数类型"
TestPostManage.post_id = resp["data"]
logging.info(f"创建岗位成功岗位ID: {TestPostManage.post_id}")
@allure.story("验证获得岗位信息")
@allure.title("测试获得岗位信息接口")
def test_joyhub_post_get_get(self):
"""测试获得岗位信息接口"""
if not TestPostManage.post_id:
pytest.skip("没有可用的岗位ID跳过测试")
with allure.step("1. 准备请求参数"):
params = {"id": TestPostManage.post_id}
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用接口"):
resp = self.test_case.kw_joyhub_post_get_get(post_id=TestPostManage.post_id)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert "id" in resp["data"], "响应中缺少id字段"
assert resp["data"]["id"] == TestPostManage.post_id, "返回的岗位ID与请求不一致"
logging.info("获得岗位信息接口验证通过")
@allure.story("验证修改岗位")
@allure.title("测试修改岗位接口")
def test_joyhub_post_update_put(self):
"""测试修改岗位接口"""
with allure.step("1. 先创建一个测试岗位"):
timestamp = int(time.time())
create_resp = self.test_case.kw_joyhub_post_create_post(
name=f"修改测试岗位_{timestamp}",
code=f"update_test_post_{timestamp}",
sort=888,
status=1
)
post_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None
if not post_id:
pytest.skip("创建测试岗位失败,跳过修改测试")
allure.attach(json.dumps({"id": post_id}, ensure_ascii=False), name="待修改岗位ID", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 准备修改参数"):
params = {
"post_id": post_id,
"name": f"测试岗位_修改_{timestamp}",
"code": f"test_post_updated_{timestamp}",
"sort": 200,
"status": 1,
"remark": "修改后的备注"
}
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
with allure.step("3. 调用修改接口"):
resp = self.test_case.kw_joyhub_post_update_put(**params)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("4. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert resp["data"] is True, "修改岗位失败"
logging.info("修改岗位接口验证通过")
@allure.story("验证删除岗位")
@allure.title("测试删除岗位接口")
def test_joyhub_post_delete_post(self):
"""测试删除岗位接口"""
with allure.step("1. 先创建一个测试岗位"):
timestamp = int(time.time())
create_resp = self.test_case.kw_joyhub_post_create_post(
name=f"删除测试岗位_{timestamp}",
code=f"delete_test_post_{timestamp}",
sort=999,
status=1
)
post_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None
if not post_id:
pytest.skip("创建测试岗位失败,跳过删除测试")
allure.attach(json.dumps({"id": post_id}, ensure_ascii=False), name="待删除岗位ID", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用删除接口"):
resp = self.test_case.kw_joyhub_post_delete_post(post_id=post_id)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
# 错误码1002005004表示岗位被引用允许这种情况通过
if resp["code"] == 1002005004:
logging.warning(f"岗位已被引用无法删除code={resp.get('code')}msg={resp.get('msg')}")
pytest.skip("岗位已被其他数据引用,跳过删除测试")
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert resp["data"] is True, "删除岗位失败"
logging.info("删除岗位接口验证通过")
@allure.story("验证批量删除岗位")
@allure.title("测试批量删除岗位接口")
def test_joyhub_post_delete_list_post(self):
"""测试批量删除岗位接口"""
with allure.step("1. 先创建两个测试岗位"):
timestamp = int(time.time())
resp1 = self.test_case.kw_joyhub_post_create_post(
name=f"批量删除测试岗位1_{timestamp}",
code=f"batch_delete_test_1_{timestamp}",
sort=300,
status=1
)
resp2 = self.test_case.kw_joyhub_post_create_post(
name=f"批量删除测试岗位2_{timestamp}",
code=f"batch_delete_test_2_{timestamp}",
sort=301,
status=1
)
post_id_1 = resp1.get("data") if resp1 and resp1.get("code") == 0 else None
post_id_2 = resp2.get("data") if resp2 and resp2.get("code") == 0 else None
if not post_id_1 or not post_id_2:
pytest.skip("创建测试岗位失败,跳过批量删除测试")
ids = [post_id_1, post_id_2]
allure.attach(json.dumps({"ids": ids}, ensure_ascii=False), name="待删除岗位ID", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用批量删除接口"):
resp = self.test_case.kw_joyhub_post_delete_list_post(ids=ids)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
# 错误码1002005004表示岗位被引用允许这种情况通过
if resp["code"] == 1002005004:
logging.warning(f"岗位已被引用无法删除code={resp.get('code')}msg={resp.get('msg')}")
pytest.skip("岗位已被其他数据引用,跳过批量删除测试")
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert resp["data"] is True, "批量删除岗位失败"
logging.info("批量删除岗位接口验证通过")
@allure.story("验证获取岗位全列表")
@allure.title("测试获取岗位全列表接口")
def test_joyhub_post_list_all_simple_get(self):
"""测试获取岗位全列表接口"""
with allure.step("1. 调用接口"):
resp = self.test_case.kw_joyhub_post_list_all_simple_get()
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("2. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert isinstance(resp["data"], list), "data字段不是数组类型"
logging.info("获取岗位全列表接口验证通过")
@allure.story("验证获取岗位精简列表")
@allure.title("测试获取岗位精简列表接口")
def test_joyhub_post_simple_list_get(self):
"""测试获取岗位精简列表接口"""
with allure.step("1. 调用接口"):
resp = self.test_case.kw_joyhub_post_simple_list_get()
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("2. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert isinstance(resp["data"], list), "data字段不是数组类型"
logging.info("获取岗位精简列表接口验证通过")

View File

@@ -0,0 +1,433 @@
# -*- coding: utf-8 -*-
# 作者 周琦 2026/04/30
"""
JoyHub 角色管理测试用例
"""
import allure
import logging
import json
import requests
from dulizhan.library.BusinessKw.JoyHub.RoleManage import RoleManage
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
@allure.feature('管理后台 - 角色模块')
class TestRoleManage(object):
test_case = RoleManage()
created_role_id = None
token_set = False
@classmethod
def setup_class(cls):
"""在整个测试类开始时登录一次所有测试用例共享token"""
logging.info("=============================================")
logging.info("=========== 开始登录获取Token ============")
logging.info("=============================================")
username = "joytest"
password = "Zhou1599"
# 直接调用登录接口(不使用加密头)
url = "https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev"
payload = {"username": username, "password": password}
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
try:
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
login_response = response.json()
if login_response and login_response.get('code') == 0:
token = login_response.get('data', {}).get('accessToken', '')
if token:
cls.test_case.set_joyhub_token(token)
cls.token_set = True
logging.info("登录成功获取到Token: {}...".format(token[:20]))
else:
logging.warning("登录成功但未获取到Token")
else:
logging.error("登录失败: {}".format(login_response))
except Exception as e:
logging.error("登录异常: {}".format(str(e)))
logging.info("=============================================")
logging.info("=========== 登录完成 ============")
logging.info("=============================================")
def setup_method(self):
"""每个测试用例执行前的准备工作"""
if not self.token_set:
logging.warning("Token未设置可能影响后续接口调用")
logging.info("-----------------------------Test Start-------------------------------")
def teardown_method(self):
logging.info("-----------------------------Test End-------------------------------")
@allure.story("验证获得角色分页列表")
def test_joyhub_role_page_get(self):
"""测试角色分页列表查询"""
with allure.step("准备查询参数"):
page_no = 1
page_size = 10
params = {"pageNo": page_no, "pageSize": page_size}
allure.attach(json.dumps(params, ensure_ascii=False, indent=2), "请求参数", attachment_type=allure.attachment_type.JSON)
logging.info("查询角色分页列表pageNo: {}, pageSize: {}".format(page_no, page_size))
with allure.step("调用查询接口"):
response_data = self.test_case.kw_joyhub_role_page_get(
note="获得角色分页列表",
pageNo=page_no,
pageSize=page_size
)
allure.attach(json.dumps(response_data, ensure_ascii=False, indent=2), "响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("验证响应数据"):
assert response_data is not None, "响应数据不能为空"
logging.info("断言: 响应数据不为空 ✓")
assert 'code' in response_data, "响应数据中缺少code字段"
logging.info("断言: 响应数据包含code字段 ✓")
assert response_data['code'] == 0, "接口调用失败code: {}, msg: {}".format(
response_data.get('code'), response_data.get('msg', '未知错误'))
logging.info("断言: 接口调用成功code=0 ✓")
assert 'data' in response_data, "响应数据中缺少data字段"
logging.info("断言: 响应数据包含data字段 ✓")
assert response_data['data'] is not None, "响应数据中的data字段不能为空"
logging.info("断言: data字段不为空 ✓")
data = response_data.get('data', {})
assert isinstance(data, dict), "data字段应为字典类型"
logging.info("断言: data字段为字典类型 ✓")
if 'records' in data:
assert isinstance(data['records'], list), "records字段应为列表类型"
logging.info("断言: records字段为列表类型 ✓,记录数: {}".format(len(data['records'])))
logging.info("✓ 角色分页列表查询成功")
@allure.story("验证新增角色")
def test_joyhub_role_create_post(self):
"""测试新增角色"""
import random
with allure.step("准备新增角色参数"):
role_name = "测试角色{}".format(random.randint(1000, 9999))
role_code = "TEST_ROLE_{}".format(random.randint(1000, 9999))
payload = {
"name": role_name,
"code": role_code,
"sort": 100,
"status": 1,
"remark": "测试角色备注"
}
allure.attach(json.dumps(payload, ensure_ascii=False, indent=2), "请求参数", attachment_type=allure.attachment_type.JSON)
logging.info("准备新增角色: {}".format(role_name))
with allure.step("调用新增角色接口"):
response_data = self.test_case.kw_joyhub_role_create_post(
note="新增角色",
**payload
)
allure.attach(json.dumps(response_data, ensure_ascii=False, indent=2), "响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("验证响应数据"):
assert response_data is not None, "响应数据不能为空"
logging.info("断言: 响应数据不为空 ✓")
assert 'code' in response_data, "响应数据中缺少code字段"
logging.info("断言: 响应数据包含code字段 ✓")
assert response_data['code'] == 0, "接口调用失败code: {}, msg: {}".format(
response_data.get('code'), response_data.get('msg', '未知错误'))
logging.info("断言: 接口调用成功code=0 ✓")
assert 'data' in response_data, "响应数据中缺少data字段"
logging.info("断言: 响应数据包含data字段 ✓")
assert response_data['data'] is not None, "响应数据中的data字段不能为空"
logging.info("断言: data字段不为空 ✓")
assert isinstance(response_data['data'], int), "data字段应为整数类型"
logging.info("断言: data字段为整数类型 ✓")
logging.info("✓ 新增角色成功角色ID: {}".format(response_data['data']))
self.created_role_id = response_data['data']
@allure.story("验证获得角色详情")
def test_joyhub_role_get_get(self):
"""测试角色详情查询"""
import random
with allure.step("创建测试角色"):
role_name = "测试角色详情{}".format(random.randint(1000, 9999))
role_code = "TEST_ROLE_DETAIL_{}".format(random.randint(1000, 9999))
create_resp = self.test_case.kw_joyhub_role_create_post(
note="创建测试角色",
name=role_name,
code=role_code,
sort=200,
status=1
)
role_id = create_resp.get('data')
logging.info("创建测试角色成功角色ID: {}".format(role_id))
with allure.step("调用查询角色详情接口"):
params = {"id": role_id}
allure.attach(json.dumps(params, ensure_ascii=False, indent=2), "请求参数", attachment_type=allure.attachment_type.JSON)
response_data = self.test_case.kw_joyhub_role_get_get(
note="获得角色信息",
id=role_id
)
allure.attach(json.dumps(response_data, ensure_ascii=False, indent=2), "响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("验证响应数据"):
assert response_data is not None, "响应数据不能为空"
logging.info("断言: 响应数据不为空 ✓")
assert 'code' in response_data, "响应数据中缺少code字段"
logging.info("断言: 响应数据包含code字段 ✓")
assert response_data['code'] == 0, "接口调用失败code: {}, msg: {}".format(
response_data.get('code'), response_data.get('msg', '未知错误'))
logging.info("断言: 接口调用成功code=0 ✓")
assert 'data' in response_data, "响应数据中缺少data字段"
logging.info("断言: 响应数据包含data字段 ✓")
assert response_data['data'] is not None, "响应数据中的data字段不能为空"
logging.info("断言: data字段不为空 ✓")
data = response_data.get('data', {})
assert 'id' in data, "角色详情中缺少id字段"
logging.info("断言: 角色详情包含id字段 ✓")
assert data['id'] == role_id, "返回的角色ID与请求不一致"
logging.info("断言: 返回的角色ID与请求一致 ✓")
assert 'name' in data, "角色详情中缺少name字段"
logging.info("断言: 角色详情包含name字段 ✓")
assert data['name'] == role_name, "返回的角色名称与创建时不一致"
logging.info("断言: 返回的角色名称与创建时一致 ✓")
logging.info("✓ 角色详情查询成功")
@allure.story("验证修改角色")
def test_joyhub_role_update_put(self):
"""测试修改角色"""
import random
with allure.step("创建测试角色"):
role_name = "测试角色修改{}".format(random.randint(1000, 9999))
role_code = "TEST_ROLE_UPDATE_{}".format(random.randint(1000, 9999))
create_resp = self.test_case.kw_joyhub_role_create_post(
note="创建测试角色",
name=role_name,
code=role_code,
sort=300,
status=1
)
role_id = create_resp.get('data')
logging.info("创建测试角色成功角色ID: {}".format(role_id))
with allure.step("准备修改参数"):
new_name = "修改后的角色名称{}".format(random.randint(1000, 9999))
payload = {
"id": role_id,
"name": new_name,
"code": role_code,
"sort": 301,
"status": 1,
"remark": "修改后的备注"
}
allure.attach(json.dumps(payload, ensure_ascii=False, indent=2), "请求参数", attachment_type=allure.attachment_type.JSON)
logging.info("准备修改角色,新名称: {}".format(new_name))
with allure.step("调用修改角色接口"):
response_data = self.test_case.kw_joyhub_role_update_put(
note="修改角色",
**payload
)
allure.attach(json.dumps(response_data, ensure_ascii=False, indent=2), "响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("验证响应数据"):
assert response_data is not None, "响应数据不能为空"
logging.info("断言: 响应数据不为空 ✓")
assert 'code' in response_data, "响应数据中缺少code字段"
logging.info("断言: 响应数据包含code字段 ✓")
assert response_data['code'] == 0, "接口调用失败code: {}, msg: {}".format(
response_data.get('code'), response_data.get('msg', '未知错误'))
logging.info("断言: 接口调用成功code=0 ✓")
assert 'data' in response_data, "响应数据中缺少data字段"
logging.info("断言: 响应数据包含data字段 ✓")
assert response_data['data'] is True, "角色修改失败"
logging.info("断言: 角色修改成功 ✓")
logging.info("✓ 修改角色成功")
@allure.story("验证删除角色")
def test_joyhub_role_delete_post(self):
"""测试删除角色"""
import random
with allure.step("创建测试角色"):
role_name = "测试角色删除{}".format(random.randint(1000, 9999))
role_code = "TEST_ROLE_DELETE_{}".format(random.randint(1000, 9999))
create_resp = self.test_case.kw_joyhub_role_create_post(
note="创建测试角色",
name=role_name,
code=role_code,
sort=400,
status=1
)
role_id = create_resp.get('data')
logging.info("创建测试角色成功角色ID: {}".format(role_id))
with allure.step("准备删除参数"):
payload = {"id": role_id}
allure.attach(json.dumps(payload, ensure_ascii=False, indent=2), "请求参数", attachment_type=allure.attachment_type.JSON)
logging.info("准备删除角色角色ID: {}".format(role_id))
with allure.step("调用删除接口"):
response_data = self.test_case.kw_joyhub_role_delete_post(
note="删除角色",
id=role_id
)
allure.attach(json.dumps(response_data, ensure_ascii=False, indent=2), "响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("验证响应数据"):
assert response_data is not None, "响应数据不能为空"
logging.info("断言: 响应数据不为空 ✓")
assert 'code' in response_data, "响应数据中缺少code字段"
logging.info("断言: 响应数据包含code字段 ✓")
assert response_data['code'] == 0, "接口调用失败code: {}, msg: {}".format(
response_data.get('code'), response_data.get('msg', '未知错误'))
logging.info("断言: 接口调用成功code=0 ✓")
assert 'data' in response_data, "响应数据中缺少data字段"
logging.info("断言: 响应数据包含data字段 ✓")
assert response_data['data'] is True, "角色删除失败"
logging.info("断言: 角色删除成功 ✓")
logging.info("✓ 删除角色成功")
@allure.story("验证批量删除角色")
def test_joyhub_role_delete_list_post(self):
"""测试批量删除角色"""
import random
with allure.step("创建测试角色"):
role_ids = []
for i in range(2):
role_name = "测试批量删除角色{}".format(random.randint(1000, 9999))
role_code = "TEST_ROLE_BATCH_{}_{}".format(random.randint(1000, 9999), i)
create_resp = self.test_case.kw_joyhub_role_create_post(
note="创建测试角色{}".format(i),
name=role_name,
code=role_code,
sort=500 + i,
status=1
)
role_ids.append(create_resp.get('data'))
logging.info("创建测试角色成功角色ID列表: {}".format(role_ids))
with allure.step("准备批量删除参数"):
payload = {"ids": role_ids}
allure.attach(json.dumps(payload, ensure_ascii=False, indent=2), "请求参数", attachment_type=allure.attachment_type.JSON)
logging.info("准备批量删除角色")
with allure.step("调用批量删除接口"):
response_data = self.test_case.kw_joyhub_role_delete_list_post(
note="批量删除角色",
ids=role_ids
)
allure.attach(json.dumps(response_data, ensure_ascii=False, indent=2), "响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("验证响应数据"):
assert response_data is not None, "响应数据不能为空"
logging.info("断言: 响应数据不为空 ✓")
assert 'code' in response_data, "响应数据中缺少code字段"
logging.info("断言: 响应数据包含code字段 ✓")
assert response_data['code'] == 0, "接口调用失败code: {}, msg: {}".format(
response_data.get('code'), response_data.get('msg', '未知错误'))
logging.info("断言: 接口调用成功code=0 ✓")
assert 'data' in response_data, "响应数据中缺少data字段"
logging.info("断言: 响应数据包含data字段 ✓")
assert response_data['data'] is True, "批量删除失败"
logging.info("断言: 批量删除成功 ✓")
logging.info("✓ 批量删除角色成功")
@allure.story("验证获取角色精简信息列表")
def test_joyhub_role_simple_list_get(self):
"""测试获取角色精简信息列表"""
with allure.step("调用查询接口"):
response_data = self.test_case.kw_joyhub_role_simple_list_get(
note="获取角色精简信息列表"
)
allure.attach(json.dumps(response_data, ensure_ascii=False, indent=2), "响应数据", attachment_type=allure.attachment_type.JSON)
logging.info("获取角色精简信息列表")
with allure.step("验证响应数据"):
assert response_data is not None, "响应数据不能为空"
logging.info("断言: 响应数据不为空 ✓")
assert 'code' in response_data, "响应数据中缺少code字段"
logging.info("断言: 响应数据包含code字段 ✓")
assert response_data['code'] == 0, "接口调用失败code: {}, msg: {}".format(
response_data.get('code'), response_data.get('msg', '未知错误'))
logging.info("断言: 接口调用成功code=0 ✓")
assert 'data' in response_data, "响应数据中缺少data字段"
logging.info("断言: 响应数据包含data字段 ✓")
assert isinstance(response_data['data'], list), "data字段应为列表类型"
logging.info("断言: data字段为列表类型 ✓,记录数: {}".format(len(response_data['data'])))
logging.info("✓ 角色精简信息列表查询成功")
@allure.story("验证获取所有角色精简信息列表")
def test_joyhub_role_list_all_simple_get(self):
"""测试获取所有角色精简信息列表"""
with allure.step("调用查询接口"):
response_data = self.test_case.kw_joyhub_role_list_all_simple_get(
note="获取所有角色精简信息列表"
)
allure.attach(json.dumps(response_data, ensure_ascii=False, indent=2), "响应数据", attachment_type=allure.attachment_type.JSON)
logging.info("获取所有角色精简信息列表")
with allure.step("验证响应数据"):
assert response_data is not None, "响应数据不能为空"
logging.info("断言: 响应数据不为空 ✓")
assert 'code' in response_data, "响应数据中缺少code字段"
logging.info("断言: 响应数据包含code字段 ✓")
assert response_data['code'] == 0, "接口调用失败code: {}, msg: {}".format(
response_data.get('code'), response_data.get('msg', '未知错误'))
logging.info("断言: 接口调用成功code=0 ✓")
assert 'data' in response_data, "响应数据中缺少data字段"
logging.info("断言: 响应数据包含data字段 ✓")
assert isinstance(response_data['data'], list), "data字段应为列表类型"
logging.info("断言: data字段为列表类型 ✓,记录数: {}".format(len(response_data['data'])))
logging.info("✓ 所有角色精简信息列表查询成功")

View File

@@ -0,0 +1,308 @@
import pytest
import allure
import logging
import requests
import json
import time
from dulizhan.library.BusinessKw.JoyHub.ShippingTemplateManage import ShippingTemplateManage
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
@allure.feature("管理后台 - 运费模板模块")
class TestShippingTemplateManage:
shipping_template_id = None
token_set = False
@classmethod
def setup_class(cls):
"""在整个测试类开始时登录一次所有测试用例共享token"""
logging.info("=============================================")
logging.info("=========== 开始登录获取Token ============")
logging.info("=============================================")
cls.test_case = ShippingTemplateManage()
username = "joytest"
password = "Zhou1599"
cls.test_case._clear_user_fingerprint(username)
url = "https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev"
payload = {"username": username, "password": password}
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
try:
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
login_response = response.json()
if login_response and login_response.get('code') == 0:
token = login_response.get('data', {}).get('accessToken', '')
if token:
cls.test_case.set_joyhub_token(token)
cls.token_set = True
logging.info("登录成功获取到Token: {}...".format(token[:20]))
else:
logging.warning("登录成功但未获取到Token")
else:
logging.error("登录失败: {}".format(login_response))
except Exception as e:
logging.error("登录异常: {}".format(str(e)))
def setup_method(self):
"""每个测试方法执行前检查token"""
if not self.token_set:
pytest.skip("Token未设置跳过测试")
@allure.story("验证登录接口")
@allure.title("测试登录接口")
def test_joyhub_login_post(self):
"""登录测试用例,验证登录接口是否正常"""
with allure.step("1. 准备登录参数"):
username = "joytest"
password = "Zhou1599"
allure.attach(f"用户名: {username}, 密码: {password}", name="登录参数", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用登录接口"):
url = "https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev"
payload = {"username": username, "password": password}
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
resp = response.json()
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="登录响应", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"登录失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert "accessToken" in resp["data"], "响应中缺少accessToken字段"
logging.info("登录接口验证通过")
@allure.story("验证获得运费模板分页列表")
@allure.title("测试获得运费模板分页列表接口")
def test_joyhub_shipping_template_page_get(self):
"""测试获得运费模板分页列表接口"""
with allure.step("1. 准备请求参数"):
params = {"page_no": 1, "page_size": 10}
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用接口"):
resp = self.test_case.kw_joyhub_shipping_template_page_get(**params)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert "list" in resp["data"], "响应中缺少list字段"
assert isinstance(resp["data"]["list"], list), "list字段不是数组类型"
logging.info("获得运费模板分页列表接口验证通过")
@allure.story("验证创建运费模板")
@allure.title("测试创建运费模板接口")
def test_joyhub_shipping_template_create_post(self):
"""测试创建运费模板接口"""
with allure.step("1. 准备请求参数"):
timestamp = int(time.time())
params = {
"template_name": f"测试模板_{timestamp}",
"is_default": 2,
"calculation_algorithm": "fixed_amount",
"currency": "USD",
"status": 1
}
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用接口"):
resp = self.test_case.kw_joyhub_shipping_template_create_post(**params)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert isinstance(resp["data"], int), "data字段不是整数类型"
TestShippingTemplateManage.shipping_template_id = resp["data"]
logging.info(f"创建运费模板成功模板ID: {TestShippingTemplateManage.shipping_template_id}")
@allure.story("验证获得运费模板详情")
@allure.title("测试获得运费模板详情接口")
def test_joyhub_shipping_template_get_detail_get(self):
"""测试获得运费模板详情(含规则与子表)接口"""
if not TestShippingTemplateManage.shipping_template_id:
pytest.skip("没有可用的运费模板ID跳过测试")
with allure.step("1. 准备请求参数"):
shipping_template_id = TestShippingTemplateManage.shipping_template_id
allure.attach(json.dumps({"id": shipping_template_id}, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用接口"):
resp = self.test_case.kw_joyhub_shipping_template_get_detail_get(shipping_template_id=shipping_template_id)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
logging.info("获得运费模板详情接口验证通过")
@allure.story("验证保存运费模板(含规则与子表)")
@allure.title("测试保存运费模板(含规则与子表)接口")
def test_joyhub_shipping_template_save_with_children_post(self):
"""测试保存运费模板信息(含规则与子表)接口"""
with allure.step("1. 准备请求参数"):
timestamp = int(time.time())
params = {
"template_name": f"测试模板_含规则_{timestamp}",
"is_default": 2,
"calculation_algorithm": "fixed_amount",
"currency": "USD",
"status": 1,
"shipping_rules": []
}
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用接口"):
resp = self.test_case.kw_joyhub_shipping_template_save_with_children_post(**params)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert isinstance(resp["data"], int), "data字段不是整数类型"
logging.info(f"保存运费模板含规则与子表成功模板ID: {resp['data']}")
@allure.story("验证更新运费模板")
@allure.title("测试更新运费模板接口")
def test_joyhub_shipping_template_update_put(self):
"""测试更新运费模板接口"""
with allure.step("1. 先创建一个测试运费模板"):
timestamp = int(time.time())
create_resp = self.test_case.kw_joyhub_shipping_template_create_post(
template_name=f"待修改模板_{timestamp}",
is_default=2,
calculation_algorithm="fixed_amount",
currency="USD",
status=1
)
shipping_template_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None
if not shipping_template_id:
pytest.skip("创建测试运费模板失败,跳过更新测试")
allure.attach(json.dumps({"id": shipping_template_id}, ensure_ascii=False), name="待修改模板ID", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 准备修改参数"):
params = {
"id": shipping_template_id,
"template_name": f"测试模板_修改_{timestamp}",
"is_default": 2,
"calculation_algorithm": "percentage",
"currency": "CNY",
"status": 2
}
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
with allure.step("3. 调用更新接口"):
resp = self.test_case.kw_joyhub_shipping_template_update_put(**params)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("4. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert resp["data"] is True, "更新运费模板失败"
logging.info("更新运费模板接口验证通过")
@allure.story("验证删除运费模板")
@allure.title("测试删除运费模板接口")
def test_joyhub_shipping_template_delete_post(self):
"""测试删除运费模板接口"""
with allure.step("1. 先创建一个测试运费模板"):
timestamp = int(time.time())
create_resp = self.test_case.kw_joyhub_shipping_template_create_post(
template_name=f"待删除模板_{timestamp}",
is_default=2,
calculation_algorithm="fixed_amount",
currency="USD",
status=1
)
shipping_template_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None
if not shipping_template_id:
pytest.skip("创建测试运费模板失败,跳过删除测试")
allure.attach(json.dumps({"id": shipping_template_id}, ensure_ascii=False), name="待删除模板ID", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 先停用模板(启用的不能删)"):
update_resp = self.test_case.kw_joyhub_shipping_template_update_put(
id=shipping_template_id,
template_name=f"待删除模板_{timestamp}",
is_default=2,
calculation_algorithm="fixed_amount",
currency="USD",
status=2
)
if update_resp.get("code") != 0:
pytest.skip("停用模板失败,跳过删除测试")
logging.info(f"已停用模板 {shipping_template_id}")
with allure.step("3. 调用删除接口"):
resp = self.test_case.kw_joyhub_shipping_template_delete_post(shipping_template_id=shipping_template_id)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("4. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert resp["data"] is True, "删除运费模板失败"
logging.info("删除运费模板接口验证通过")
@allure.story("验证批量删除运费模板")
@allure.title("测试批量删除运费模板接口")
def test_joyhub_shipping_template_delete_list_post(self):
"""测试批量删除运费模板接口"""
with allure.step("1. 先创建两个测试运费模板"):
timestamp = int(time.time())
resp1 = self.test_case.kw_joyhub_shipping_template_create_post(
template_name=f"批量删除模板1_{timestamp}",
is_default=2,
calculation_algorithm="fixed_amount",
currency="USD",
status=1
)
resp2 = self.test_case.kw_joyhub_shipping_template_create_post(
template_name=f"批量删除模板2_{timestamp}",
is_default=2,
calculation_algorithm="fixed_amount",
currency="USD",
status=1
)
template_id_1 = resp1.get("data") if resp1 and resp1.get("code") == 0 else None
template_id_2 = resp2.get("data") if resp2 and resp2.get("code") == 0 else None
if not template_id_1 or not template_id_2:
pytest.skip("创建测试运费模板失败,跳过批量删除测试")
ids = [template_id_1, template_id_2]
allure.attach(json.dumps({"ids": ids}, ensure_ascii=False), name="待删除模板ID", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用批量删除接口"):
resp = self.test_case.kw_joyhub_shipping_template_delete_list_post(ids=ids)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert resp["data"] is True, "批量删除运费模板失败"
logging.info("批量删除运费模板接口验证通过")

View File

@@ -0,0 +1,174 @@
import pytest
import allure
import logging
import requests
import json
from dulizhan.library.BusinessKw.JoyHub.UserProfile import UserProfile
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
@allure.feature("管理后台 - 用户个人中心模块")
class TestUserProfile:
token_set = False
original_password = "Zhou1599"
test_password = "Aa123456"
@classmethod
def setup_class(cls):
"""在整个测试类开始时登录一次所有测试用例共享token"""
logging.info("=============================================")
logging.info("=========== 开始登录获取Token ============")
logging.info("=============================================")
cls.test_case = UserProfile()
username = "joytest"
password = cls.original_password
cls.test_case._clear_user_fingerprint(username)
url = "https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev"
payload = {"username": username, "password": password}
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
try:
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
login_response = response.json()
if login_response and login_response.get('code') == 0:
token = login_response.get('data', {}).get('accessToken', '')
if token:
cls.test_case.set_joyhub_token(token)
cls.token_set = True
logging.info("登录成功获取到Token: {}...".format(token[:20]))
else:
logging.warning("登录成功但未获取到Token")
else:
logging.error("登录失败: {}".format(login_response))
except Exception as e:
logging.error("登录异常: {}".format(str(e)))
def setup_method(self):
"""每个测试方法执行前检查token"""
if not self.token_set:
pytest.skip("Token未设置跳过测试")
@classmethod
def teardown_class(cls):
"""测试类结束后,确保密码改回原密码"""
logging.info("=============================================")
logging.info("=========== 测试结束,恢复原密码 ============")
logging.info("=============================================")
try:
# 先用测试密码登录
url = "https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev"
payload = {"username": "joytest", "password": cls.test_password}
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
login_response = response.json()
if login_response and login_response.get('code') == 0:
token = login_response.get('data', {}).get('accessToken', '')
if token:
# 修改回原密码
cls.test_case.set_joyhub_token(token)
resp = cls.test_case.kw_joyhub_user_profile_update_password_put(
old_password=cls.test_password,
new_password=cls.original_password
)
if resp and resp.get('code') == 0:
logging.info("密码已恢复为原密码: {}".format(cls.original_password))
else:
logging.warning("恢复原密码失败: {}".format(resp))
except Exception as e:
logging.error("恢复原密码异常: {}".format(str(e)))
@allure.story("验证获得登录用户信息")
@allure.title("测试获得登录用户信息接口")
def test_joyhub_user_profile_get_get(self):
"""测试获得登录用户信息接口"""
with allure.step("1. 调用接口"):
resp = self.test_case.kw_joyhub_user_profile_get_get()
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("2. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert "id" in resp["data"], "响应中缺少id字段"
assert "username" in resp["data"], "响应中缺少username字段"
logging.info("获得登录用户信息接口验证通过")
@allure.story("验证修改用户个人信息")
@allure.title("测试修改用户个人信息接口")
def test_joyhub_user_profile_update_put(self):
"""测试修改用户个人信息接口"""
with allure.step("1. 先获取当前用户信息"):
get_resp = self.test_case.kw_joyhub_user_profile_get_get()
if not get_resp or get_resp.get('code') != 0:
pytest.skip("获取用户信息失败,跳过修改测试")
original_data = get_resp.get('data', {})
allure.attach(json.dumps(original_data, ensure_ascii=False, indent=2), name="原始用户信息", attachment_type=allure.attachment_type.JSON)
with allure.step("2. 准备修改参数"):
params = {
"nickname": "测试用户_修改",
"email": "test_updated@example.com",
"mobile": "13900139000",
"sex": 1
}
allure.attach(json.dumps(params, ensure_ascii=False), name="修改参数", attachment_type=allure.attachment_type.TEXT)
with allure.step("3. 调用修改接口"):
resp = self.test_case.kw_joyhub_user_profile_update_put(**params)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("4. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert resp["data"] is True, "修改用户个人信息失败"
logging.info("修改用户个人信息接口验证通过")
with allure.step("5. 恢复原始信息"):
# 恢复原始信息
restore_params = {
"nickname": original_data.get("nickname", ""),
"email": original_data.get("email", ""),
"mobile": original_data.get("mobile", ""),
"sex": original_data.get("sex"),
"avatar": original_data.get("avatar", "")
}
restore_resp = self.test_case.kw_joyhub_user_profile_update_put(**restore_params)
if restore_resp and restore_resp.get('code') == 0:
logging.info("用户信息已恢复")
else:
logging.warning("恢复用户信息失败: {}".format(restore_resp))
@allure.story("验证修改用户个人密码")
@allure.title("测试修改用户个人密码接口")
def test_joyhub_user_profile_update_password_put(self):
"""测试修改用户个人密码接口"""
with allure.step("1. 准备修改密码参数"):
params = {
"old_password": self.original_password,
"new_password": self.test_password
}
allure.attach(json.dumps({"oldPassword": "******", "newPassword": "******"}, ensure_ascii=False), name="修改参数", attachment_type=allure.attachment_type.TEXT)
with allure.step("2. 调用修改密码接口"):
resp = self.test_case.kw_joyhub_user_profile_update_password_put(**params)
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("3. 验证响应"):
assert resp is not None, "响应为空"
assert "code" in resp, "响应中缺少code字段"
assert resp["code"] == 0, f"请求失败code={resp.get('code')}"
assert "data" in resp, "响应中缺少data字段"
assert resp["data"] is True, "修改用户个人密码失败"
logging.info("修改用户个人密码接口验证通过,密码已修改为: {}".format(self.test_password))
logging.info("注意:测试类结束后将自动恢复原密码: {}".format(self.original_password))

View File

@@ -0,0 +1,534 @@
# -*- coding: utf-8 -*-
# 作者 周琦 2026/04/28
import allure
import logging
import requests
import json
from dulizhan.library.BusinessKw.JoyHub.UserManage import UserManage
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
@allure.feature('管理后台 - 用户模块')
class TestUserManage(object):
test_case = UserManage()
token_set = False
@classmethod
def setup_class(cls):
"""在整个测试类开始时登录一次所有测试用例共享token"""
logging.info("=============================================")
logging.info("=========== 开始登录获取Token ============")
logging.info("=============================================")
username = "joytest"
password = "Zhou1599"
# 清除指纹
cls.test_case._clear_user_fingerprint(username)
# 直接调用登录接口(不使用加密头)
url = "https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev"
payload = {"username": username, "password": password}
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
try:
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
login_response = response.json()
if login_response and login_response.get('code') == 0:
token = login_response.get('data', {}).get('accessToken', '')
if token:
cls.test_case.set_joyhub_token(token)
cls.token_set = True
logging.info("登录成功获取到Token: {}...".format(token[:20]))
else:
logging.warning("登录成功但未获取到Token")
else:
logging.error("登录失败: {}".format(login_response))
except Exception as e:
logging.error("登录异常: {}".format(str(e)))
logging.info("=============================================")
logging.info("=========== 登录完成 ============")
logging.info("=============================================")
def setup_method(self):
"""每个测试用例执行前的准备工作"""
if not self.token_set:
logging.warning("Token未设置可能影响后续接口调用")
logging.info("-----------------------------Test Start-------------------------------")
def teardown_method(self):
logging.info("-----------------------------Test End-------------------------------")
@allure.story("验证用户登录")
def test_joyhub_login_post(self):
"""登录测试用例验证登录接口是否正常token已在setup_class中设置"""
with allure.step("准备登录参数"):
username = "joytest"
password = "Zhou1599"
url = "https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev"
payload = {"username": username, "password": password}
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
allure.attach(json.dumps(payload, ensure_ascii=False, indent=2), "请求参数", attachment_type=allure.attachment_type.JSON)
logging.info("准备登录请求,用户名: {}".format(username))
with allure.step("发送登录请求"):
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
response_data = response.json()
allure.attach(json.dumps(response_data, ensure_ascii=False, indent=2), "响应数据", attachment_type=allure.attachment_type.JSON)
logging.info("登录请求响应状态码: {}".format(response.status_code))
with allure.step("验证响应数据结构"):
assert response_data is not None, "响应数据不能为空"
logging.info("断言: 响应数据不为空 ")
assert 'code' in response_data, "响应数据中缺少code字段"
logging.info("断言: 响应数据包含code字段 ")
assert response_data['code'] == 0, "接口调用失败code: {}, msg: {}".format(
response_data.get('code'), response_data.get('msg', '未知错误'))
logging.info("断言: 接口调用成功code=0 ")
with allure.step("验证返回数据"):
assert 'data' in response_data, "响应数据中缺少data字段"
logging.info("断言: 响应数据包含data字段 ")
assert response_data['data'] is not None, "响应数据中的data字段不能为空"
logging.info("断言: data字段不为空 ")
data = response_data.get('data', {})
assert 'accessToken' in data, "响应数据中缺少accessToken字段"
logging.info("断言: data包含accessToken字段 ")
assert 'userId' in data, "响应数据中缺少userId字段"
logging.info("断言: data包含userId字段 ")
assert data.get('accessToken'), "accessToken不能为空"
logging.info("断言: accessToken不为空 ")
logging.info("用户登录成功userId: {}, token: {}...".format(
data.get('userId'), data.get('accessToken', '')[:20]))
logging.info("注意: Token已在setup_class中统一设置此用例仅验证登录功能")
@allure.story("验证获得用户分页列表")
def test_joyhub_user_page_get(self):
with allure.step("准备查询参数"):
page_no = 1
page_size = 10
params = {"pageNo": page_no, "pageSize": page_size}
allure.attach(json.dumps(params, ensure_ascii=False, indent=2), "请求参数", attachment_type=allure.attachment_type.JSON)
logging.info("查询用户分页列表pageNo: {}, pageSize: {}".format(page_no, page_size))
with allure.step("调用查询接口"):
response_data = self.test_case.kw_joyhub_user_page_get(
note="获得用户分页列表",
pageNo=page_no,
pageSize=page_size
)
allure.attach(json.dumps(response_data, ensure_ascii=False, indent=2), "响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("验证响应数据"):
assert response_data is not None, "响应数据不能为空"
logging.info("断言: 响应数据不为空 ✓")
assert 'code' in response_data, "响应数据中缺少code字段"
logging.info("断言: 响应数据包含code字段 ✓")
assert response_data['code'] == 0, "接口调用失败code: {}, msg: {}".format(
response_data.get('code'), response_data.get('msg', '未知错误'))
logging.info("断言: 接口调用成功code=0 ✓")
assert 'data' in response_data, "响应数据中缺少data字段"
logging.info("断言: 响应数据包含data字段 ✓")
assert response_data['data'] is not None, "响应数据中的data字段不能为空"
logging.info("断言: data字段不为空 ✓")
data = response_data.get('data', {})
assert isinstance(data, dict), "data字段应为字典类型"
logging.info("断言: data字段为字典类型 ✓")
if 'records' in data:
assert isinstance(data['records'], list), "records字段应为列表类型"
logging.info("断言: records字段为列表类型 ✓,记录数: {}".format(len(data['records'])))
logging.info("✓ 用户分页列表查询成功")
@allure.story("验证获取用户精简信息列表")
def test_joyhub_user_simple_list_get(self):
with allure.step("调用查询接口"):
response_data = self.test_case.kw_joyhub_user_simple_list_get(
note="获取用户精简信息列表"
)
allure.attach(json.dumps(response_data, ensure_ascii=False, indent=2), "响应数据", attachment_type=allure.attachment_type.JSON)
logging.info("获取用户精简信息列表")
with allure.step("验证响应数据"):
assert response_data is not None, "响应数据不能为空"
logging.info("断言: 响应数据不为空 ✓")
assert 'code' in response_data, "响应数据中缺少code字段"
logging.info("断言: 响应数据包含code字段 ✓")
assert response_data['code'] == 0, "接口调用失败code: {}, msg: {}".format(
response_data.get('code'), response_data.get('msg', '未知错误'))
logging.info("断言: 接口调用成功code=0 ✓")
assert 'data' in response_data, "响应数据中缺少data字段"
logging.info("断言: 响应数据包含data字段 ✓")
assert isinstance(response_data['data'], list), "data字段应为列表类型"
logging.info("断言: data字段为列表类型 ✓,记录数: {}".format(len(response_data['data'])))
logging.info("✓ 用户精简信息列表查询成功")
@allure.story("验证新增用户")
def test_joyhub_user_create_post(self):
import random
with allure.step("准备新增用户参数"):
username = "testuser{}".format(random.randint(100000, 999999))
nickname = "测试用户{}".format(random.randint(1000, 9999))
password = "123456"
mobile = "138{}{}{}{}{}{}{}{}".format(random.randint(0,9), random.randint(0,9), random.randint(0,9),
random.randint(0,9), random.randint(0,9), random.randint(0,9),
random.randint(0,9), random.randint(0,9))
payload = {
"username": username,
"nickname": nickname,
"password": password,
"email": "{}@test.com".format(username),
"mobile": mobile,
"sex": 1,
"remark": "测试用户"
}
allure.attach(json.dumps(payload, ensure_ascii=False, indent=2), "请求参数", attachment_type=allure.attachment_type.JSON)
logging.info("准备新增用户: {}".format(username))
with allure.step("调用新增用户接口"):
response_data = self.test_case.kw_joyhub_user_create_post(
note="新增用户",
**payload
)
allure.attach(json.dumps(response_data, ensure_ascii=False, indent=2), "响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("验证响应数据"):
assert response_data is not None, "响应数据不能为空"
logging.info("断言: 响应数据不为空 ✓")
assert 'code' in response_data, "响应数据中缺少code字段"
logging.info("断言: 响应数据包含code字段 ✓")
assert response_data['code'] == 0, "接口调用失败code: {}, msg: {}".format(
response_data.get('code'), response_data.get('msg', '未知错误'))
logging.info("断言: 接口调用成功code=0 ✓")
assert 'data' in response_data, "响应数据中缺少data字段"
logging.info("断言: 响应数据包含data字段 ✓")
assert response_data['data'] is not None, "响应数据中的data字段不能为空"
logging.info("断言: data字段不为空 ✓")
logging.info("✓ 新增用户成功用户ID: {}".format(response_data['data']))
self.created_user_id = response_data['data']
@allure.story("验证获得用户详情")
def test_joyhub_user_get_get(self):
import random
with allure.step("创建测试用户"):
username = "testuserget{}".format(random.randint(100000, 999999))
nickname = "测试用户详情{}".format(random.randint(1000, 9999))
create_resp = self.test_case.kw_joyhub_user_create_post(
note="创建测试用户",
username=username,
nickname=nickname,
password="123456"
)
user_id = create_resp.get('data')
logging.info("创建测试用户成功用户ID: {}".format(user_id))
with allure.step("调用查询用户详情接口"):
params = {"id": user_id}
allure.attach(json.dumps(params, ensure_ascii=False, indent=2), "请求参数", attachment_type=allure.attachment_type.JSON)
response_data = self.test_case.kw_joyhub_user_get_get(
note="获得用户详情",
id=user_id
)
allure.attach(json.dumps(response_data, ensure_ascii=False, indent=2), "响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("验证响应数据"):
assert response_data is not None, "响应数据不能为空"
logging.info("断言: 响应数据不为空 ✓")
assert 'code' in response_data, "响应数据中缺少code字段"
logging.info("断言: 响应数据包含code字段 ✓")
assert response_data['code'] == 0, "接口调用失败code: {}, msg: {}".format(
response_data.get('code'), response_data.get('msg', '未知错误'))
logging.info("断言: 接口调用成功code=0 ✓")
assert 'data' in response_data, "响应数据中缺少data字段"
logging.info("断言: 响应数据包含data字段 ✓")
assert response_data['data'] is not None, "响应数据中的data字段不能为空"
logging.info("断言: data字段不为空 ✓")
data = response_data.get('data', {})
assert 'id' in data, "用户详情中缺少id字段"
logging.info("断言: 用户详情包含id字段 ✓")
assert data['id'] == user_id, "返回的用户ID与请求不一致"
logging.info("断言: 返回的用户ID与请求一致 ✓")
assert 'username' in data, "用户详情中缺少username字段"
logging.info("断言: 用户详情包含username字段 ✓")
assert data['username'] == username, "返回的用户名与创建时不一致"
logging.info("断言: 返回的用户名与创建时一致 ✓")
logging.info("✓ 用户详情查询成功")
@allure.story("验证修改用户")
def test_joyhub_user_update_put(self):
import random
with allure.step("创建测试用户"):
username = "testuserupdate{}".format(random.randint(100000, 999999))
nickname = "测试用户更新{}".format(random.randint(1000, 9999))
create_resp = self.test_case.kw_joyhub_user_create_post(
note="创建测试用户",
username=username,
nickname=nickname,
password="123456"
)
user_id = create_resp.get('data')
logging.info("创建测试用户成功用户ID: {}".format(user_id))
with allure.step("准备修改参数"):
new_nickname = "修改后的昵称{}".format(random.randint(1000, 9999))
payload = {
"id": user_id,
"username": username,
"nickname": new_nickname,
"remark": "修改后的备注"
}
allure.attach(json.dumps(payload, ensure_ascii=False, indent=2), "请求参数", attachment_type=allure.attachment_type.JSON)
logging.info("准备修改用户,新昵称: {}".format(new_nickname))
with allure.step("调用修改用户接口"):
response_data = self.test_case.kw_joyhub_user_update_put(
note="修改用户",
**payload
)
allure.attach(json.dumps(response_data, ensure_ascii=False, indent=2), "响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("验证响应数据"):
assert response_data is not None, "响应数据不能为空"
logging.info("断言: 响应数据不为空 ✓")
assert 'code' in response_data, "响应数据中缺少code字段"
logging.info("断言: 响应数据包含code字段 ✓")
assert response_data['code'] == 0, "接口调用失败code: {}, msg: {}".format(
response_data.get('code'), response_data.get('msg', '未知错误'))
logging.info("断言: 接口调用成功code=0 ✓")
assert 'data' in response_data, "响应数据中缺少data字段"
logging.info("断言: 响应数据包含data字段 ✓")
assert response_data['data'] is True, "用户修改失败"
logging.info("断言: 用户修改成功 ✓")
logging.info("✓ 修改用户成功")
@allure.story("验证重置用户密码")
def test_joyhub_user_update_password_put(self):
import random
with allure.step("创建测试用户"):
username = "testuserpwd{}".format(random.randint(100000, 999999))
create_resp = self.test_case.kw_joyhub_user_create_post(
note="创建测试用户",
username=username,
nickname="测试密码用户",
password="123456"
)
user_id = create_resp.get('data')
logging.info("创建测试用户成功用户ID: {}".format(user_id))
with allure.step("准备重置密码参数"):
payload = {"id": user_id, "password": "654321"}
allure.attach(json.dumps(payload, ensure_ascii=False, indent=2), "请求参数", attachment_type=allure.attachment_type.JSON)
logging.info("准备重置用户密码")
with allure.step("调用重置密码接口"):
response_data = self.test_case.kw_joyhub_user_update_password_put(
note="重置用户密码",
**payload
)
allure.attach(json.dumps(response_data, ensure_ascii=False, indent=2), "响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("验证响应数据"):
assert response_data is not None, "响应数据不能为空"
logging.info("断言: 响应数据不为空 ✓")
assert 'code' in response_data, "响应数据中缺少code字段"
logging.info("断言: 响应数据包含code字段 ✓")
assert response_data['code'] == 0, "接口调用失败code: {}, msg: {}".format(
response_data.get('code'), response_data.get('msg', '未知错误'))
logging.info("断言: 接口调用成功code=0 ✓")
assert 'data' in response_data, "响应数据中缺少data字段"
logging.info("断言: 响应数据包含data字段 ✓")
assert response_data['data'] is True, "密码重置失败"
logging.info("断言: 密码重置成功 ✓")
logging.info("✓ 重置用户密码成功")
@allure.story("验证修改用户状态")
def test_joyhub_user_update_status_put(self):
import random
with allure.step("创建测试用户"):
username = "testuserstatus{}".format(random.randint(100000, 999999))
create_resp = self.test_case.kw_joyhub_user_create_post(
note="创建测试用户",
username=username,
nickname="测试状态用户",
password="123456"
)
user_id = create_resp.get('data')
logging.info("创建测试用户成功用户ID: {}".format(user_id))
with allure.step("准备修改状态参数"):
payload = {"id": user_id, "status": 0}
allure.attach(json.dumps(payload, ensure_ascii=False, indent=2), "请求参数", attachment_type=allure.attachment_type.JSON)
logging.info("准备修改用户状态为: {}".format(0))
with allure.step("调用修改状态接口"):
response_data = self.test_case.kw_joyhub_user_update_status_put(
note="修改用户状态",
**payload
)
allure.attach(json.dumps(response_data, ensure_ascii=False, indent=2), "响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("验证响应数据"):
assert response_data is not None, "响应数据不能为空"
logging.info("断言: 响应数据不为空 ✓")
assert 'code' in response_data, "响应数据中缺少code字段"
logging.info("断言: 响应数据包含code字段 ✓")
assert response_data['code'] == 0, "接口调用失败code: {}, msg: {}".format(
response_data.get('code'), response_data.get('msg', '未知错误'))
logging.info("断言: 接口调用成功code=0 ✓")
assert 'data' in response_data, "响应数据中缺少data字段"
logging.info("断言: 响应数据包含data字段 ✓")
assert response_data['data'] is True, "用户状态修改失败"
logging.info("断言: 用户状态修改成功 ✓")
logging.info("✓ 修改用户状态成功")
@allure.story("验证删除用户")
def test_joyhub_user_delete_post(self):
import random
with allure.step("创建测试用户"):
username = "testuserdelete{}".format(random.randint(100000, 999999))
create_resp = self.test_case.kw_joyhub_user_create_post(
note="创建测试用户",
username=username,
nickname="测试删除用户",
password="123456"
)
user_id = create_resp.get('data')
logging.info("创建测试用户成功用户ID: {}".format(user_id))
with allure.step("准备删除参数"):
payload = {"id": user_id}
allure.attach(json.dumps(payload, ensure_ascii=False, indent=2), "请求参数", attachment_type=allure.attachment_type.JSON)
logging.info("准备删除用户用户ID: {}".format(user_id))
with allure.step("调用删除接口"):
response_data = self.test_case.kw_joyhub_user_delete_post(
note="删除用户",
id=user_id
)
allure.attach(json.dumps(response_data, ensure_ascii=False, indent=2), "响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("验证响应数据"):
assert response_data is not None, "响应数据不能为空"
logging.info("断言: 响应数据不为空 ✓")
assert 'code' in response_data, "响应数据中缺少code字段"
logging.info("断言: 响应数据包含code字段 ✓")
assert response_data['code'] == 0, "接口调用失败code: {}, msg: {}".format(
response_data.get('code'), response_data.get('msg', '未知错误'))
logging.info("断言: 接口调用成功code=0 ✓")
assert 'data' in response_data, "响应数据中缺少data字段"
logging.info("断言: 响应数据包含data字段 ✓")
assert response_data['data'] is True, "用户删除失败"
logging.info("断言: 用户删除成功 ✓")
logging.info("✓ 删除用户成功")
@allure.story("验证批量删除用户")
def test_joyhub_user_delete_list_post(self):
import random
with allure.step("创建测试用户"):
user_ids = []
for i in range(2):
username = "testuserbatch{}{}".format(random.randint(100000, 999999), i)
create_resp = self.test_case.kw_joyhub_user_create_post(
note="创建测试用户{}".format(i),
username=username,
nickname="测试批量删除用户{}".format(i),
password="123456"
)
user_ids.append(create_resp.get('data'))
logging.info("创建测试用户成功用户ID列表: {}".format(user_ids))
with allure.step("准备批量删除参数"):
payload = {"ids": user_ids}
allure.attach(json.dumps(payload, ensure_ascii=False, indent=2), "请求参数", attachment_type=allure.attachment_type.JSON)
logging.info("准备批量删除用户")
with allure.step("调用批量删除接口"):
response_data = self.test_case.kw_joyhub_user_delete_list_post(
note="批量删除用户",
ids=user_ids
)
allure.attach(json.dumps(response_data, ensure_ascii=False, indent=2), "响应数据", attachment_type=allure.attachment_type.JSON)
with allure.step("验证响应数据"):
assert response_data is not None, "响应数据不能为空"
logging.info("断言: 响应数据不为空 ✓")
assert 'code' in response_data, "响应数据中缺少code字段"
logging.info("断言: 响应数据包含code字段 ✓")
assert response_data['code'] == 0, "接口调用失败code: {}, msg: {}".format(
response_data.get('code'), response_data.get('msg', '未知错误'))
logging.info("断言: 接口调用成功code=0 ✓")
assert 'data' in response_data, "响应数据中缺少data字段"
logging.info("断言: 响应数据包含data字段 ✓")
assert response_data['data'] is True, "批量删除失败"
logging.info("断言: 批量删除成功 ✓")
logging.info("✓ 批量删除用户成功")

View File

@@ -0,0 +1,7 @@
# -*- coding:utf-8 -*-
"""
JoyHub接口测试用例模块
"""
from .Joyhub_user import TestUserManage
__all__ = ['TestUserManage']

View File

@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
import allure
import logging
from zhyy.library.BusinessKw.SZPurchase.PurchaseOrderManage import PurchaseOrder
@allure.feature('深圳采购工作台采购订单页面')
class Test_purchase_order(object):
test_case = PurchaseOrder()
def teardown_method(self):
logging.info("-----------------------------End-------------------------------")
@allure.story("验证采购工作台采购订单页面列表查询")
def test_check_purchase_order_page(self):
purchase_order_code = 'PO251209048' # 采购单号 必填
supplier_company_ids = ['334'] # 供应商id 非必填
payment_status = '0' # 付款状态 非必填
status = '0' # 采购单状态 非必填
page_no = 1 # 页码 必填
page_size = 10 # 每页条数 必填
response_data = self.test_case.kw_zhyy_get_purchase_page_post(
note="采购工作台采购订单页面列表查询",
user='purchase',
order_sn=purchase_order_code,
supplier_company_ids=supplier_company_ids,
payment_status=payment_status,
status=status,
page_no=page_no,
page_size=page_size
)
# 断言检查
assert response_data is not None, "响应数据不能为空"
assert 'code' in response_data, "响应数据中缺少code字段"
assert response_data['code'] == 0, "接口调用失败code: {}, msg: {}".format(
response_data.get('code'), response_data.get('msg', '未知错误'))
assert 'data' in response_data, "响应数据中缺少data字段"
assert response_data['data'] is not None, "响应数据中的data字段不能为空"
# 如果传入了采购单号,检查返回的数据中是否包含该采购单号
if purchase_order_code:
data = response_data.get('data', {})
order_found = False
# 检查返回的数据结构,可能包含列表或其他结构
if isinstance(data, dict):
# 如果data是字典可能包含records、list、data等字段
records = data.get('records') or data.get('list') or data.get('data') or []
if isinstance(records, list) and len(records) > 0:
# 检查列表中是否包含指定的采购单号
for item in records:
if isinstance(item, dict):
order_sn = item.get('order_sn') or item.get('orderSn') or item.get('orderSn')
if order_sn == purchase_order_code:
order_found = True
break
elif isinstance(data, list):
# 如果data本身就是列表
for item in data:
if isinstance(item, dict):
order_sn = item.get('order_sn') or item.get('orderSn') or item.get('orderSn')
if order_sn == purchase_order_code:
order_found = True
break
if order_found:
logging.info("✓ 断言通过:返回的数据中包含采购单号 {}".format(purchase_order_code))
else:
logging.warning("⚠ 警告:返回的数据中未找到采购单号: {},但接口调用成功".format(purchase_order_code))
logging.info("✓ 所有断言检查通过")
print("✓ 查询成功,响应数据: {}".format(response_data))

View File

@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
import allure
import logging
from zhyy.library.BusinessKw.SZPurchase.index import PurchaseIndex
@allure.feature('深圳采购工作台首页')
class Test_purchase_index(object):
# config = ReadConfig.ReadConfig() # 调用读取配置文件的方法类
test_case = PurchaseIndex()
def teardown_method(self):
logging.info("-----------------------------End-------------------------------")
@allure.story("验证采购工作台待办任务与在办任务功能")
def test_check_todo(self):
get_purchase_data = self.test_case.kw_zhyy_get_todo(note="采购工作台首页待办任务PO与在办任务PO", user='purchase')

View File

@@ -0,0 +1,14 @@
# -*- coding: utf-8 -*-
"""
测试配置文件
用于设置测试环境的路径和配置
"""
import os
import sys
# 添加项目根目录到 Python 路径,确保能导入 zhyy 模块
current_file_path = os.path.abspath(__file__)
# 从 test_case/TestCase/接口/conftest.py 向上找到项目根目录 d:\zhyy
project_root = os.path.abspath(os.path.join(os.path.dirname(current_file_path), '../../../..'))
if project_root not in sys.path:
sys.path.insert(0, project_root)