From 354d17989a6a0dc118e573006556f8f272f4485f Mon Sep 17 00:00:00 2001 From: zhouqi Date: Wed, 6 May 2026 15:45:45 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9EJoyHub=E5=8D=8F?= =?UTF-8?q?=E8=AE=AE=E7=AE=A1=E7=90=86=E5=92=8Capp=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=8F=B7=E7=AE=A1=E7=90=86=E6=8E=A5=E5=8F=A3=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BusinessKw/JoyHub/AgreementManage.py | 153 +++++++++ .../BusinessKw/JoyHub/AppVersionManage.py | 202 ++++++++++++ dulizhan/library/Dlizhan_interface.py | 62 +++- .../TestCase/接口/JoyHub/Joyhub_Agreement.py | 299 +++++++++++++++++ .../TestCase/接口/JoyHub/Joyhub_AppVersion.py | 302 ++++++++++++++++++ 5 files changed, 1015 insertions(+), 3 deletions(-) create mode 100644 dulizhan/library/BusinessKw/JoyHub/AgreementManage.py create mode 100644 dulizhan/library/BusinessKw/JoyHub/AppVersionManage.py create mode 100644 dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_Agreement.py create mode 100644 dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_AppVersion.py diff --git a/dulizhan/library/BusinessKw/JoyHub/AgreementManage.py b/dulizhan/library/BusinessKw/JoyHub/AgreementManage.py new file mode 100644 index 0000000..76ab13f --- /dev/null +++ b/dulizhan/library/BusinessKw/JoyHub/AgreementManage.py @@ -0,0 +1,153 @@ +# -*- coding:utf-8 -*- +import os +import sys + +current_file_path = os.path.abspath(__file__) +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) + +from dulizhan.library.Dlizhan_interface import DlzhanInterface +from base_framework.public_tools import log +import allure + +obj_log = log.get_logger() + + +class AgreementManage(DlzhanInterface): + def __init__(self): + super().__init__() + + @allure.step("创建协议") + def kw_joyhub_agreement_create_post(self, type, title, content, terminal="web", lang="en", rank_num=1, status=1, id=0): + """ + 创建协议业务关键字 + :param id: 主键,新增为0 + :param type: 类型(1隐私协议 2用户协议) + :param title: 标题 + :param content: 内容 + :param terminal: 终端(1web 2app) + :param lang: 语言 (en 英语 de 德语 ja 日语) + :param rank_num: 排序号 + :param status: 状态 (1正常 2停用) + :return: 响应结果 + """ + obj_log.info(f"创建协议 - type: {type}, title: {title}, content: {content[:50]}..., terminal: {terminal}, lang: {lang}, rank_num: {rank_num}, status: {status}") + + params = { + "id": id, + "type": type, + "title": title, + "content": content, + "terminal": terminal, + "lang": lang, + "rankNum": rank_num, + "status": status + } + + resp = self.kw_in_joyhub_agreement_create_post(**params) + obj_log.info(f"创建协议响应: {resp}") + + return resp + + @allure.step("删除协议") + def kw_joyhub_agreement_delete_delete(self, agreement_id): + """ + 删除协议业务关键字 + :param agreement_id: 协议ID + :return: 响应结果 + """ + obj_log.info(f"删除协议 - agreement_id: {agreement_id}") + + resp = self.kw_in_joyhub_agreement_delete_delete(agreement_id) + obj_log.info(f"删除协议响应: {resp}") + + return resp + + @allure.step("批量删除协议") + def kw_joyhub_agreement_delete_list_delete(self, agreement_ids): + """ + 批量删除协议业务关键字 + :param agreement_ids: 协议ID列表 + :return: 响应结果 + """ + obj_log.info(f"批量删除协议 - agreement_ids: {agreement_ids}") + + resp = self.kw_in_joyhub_agreement_delete_list_delete(agreement_ids) + obj_log.info(f"批量删除协议响应: {resp}") + + return resp + + @allure.step("导出协议Excel") + def kw_joyhub_agreement_export_excel_get(self, **kwargs): + """ + 导出协议Excel业务关键字 + :param kwargs: 查询参数(type, title, content, status) + :return: 响应结果 + """ + obj_log.info(f"导出协议Excel - 参数: {kwargs}") + + resp = self.kw_in_joyhub_agreement_export_excel_get(**kwargs) + obj_log.info(f"导出协议Excel响应: {resp}") + + return resp + + @allure.step("获得协议详情") + def kw_joyhub_agreement_get_get(self, agreement_id): + """ + 获得协议详情业务关键字 + :param agreement_id: 协议ID + :return: 响应结果 + """ + obj_log.info(f"获得协议详情 - agreement_id: {agreement_id}") + + resp = self.kw_in_joyhub_agreement_get_get(agreement_id) + obj_log.info(f"获得协议详情响应: {resp}") + + return resp + + @allure.step("获得协议分页列表") + def kw_joyhub_agreement_page_get(self, **kwargs): + """ + 获得协议分页列表业务关键字 + :param kwargs: 查询参数(type, title, content, status, page_no, page_size) + :return: 响应结果 + """ + obj_log.info(f"获得协议分页列表 - 参数: {kwargs}") + + resp = self.kw_in_joyhub_agreement_page_get(**kwargs) + obj_log.info(f"获得协议分页列表响应: {resp}") + + return resp + + @allure.step("更新协议") + def kw_joyhub_agreement_update_put(self, agreement_id, type, title, content, terminal="web", lang="en", rank_num=1, status=1): + """ + 更新协议业务关键字 + :param agreement_id: 协议ID + :param type: 类型(1隐私协议 2用户协议) + :param title: 标题 + :param content: 内容 + :param terminal: 终端(1web 2app) + :param lang: 语言 (en 英语 de 德语 ja 日语) + :param rank_num: 排序号 + :param status: 状态 (1正常 2停用) + :return: 响应结果 + """ + obj_log.info(f"更新协议 - agreement_id: {agreement_id}, type: {type}, title: {title}, content: {content[:50]}..., terminal: {terminal}, lang: {lang}, rank_num: {rank_num}, status: {status}") + + params = { + "id": agreement_id, + "type": type, + "title": title, + "content": content, + "terminal": terminal, + "lang": lang, + "rankNum": rank_num, + "status": status + } + + resp = self.kw_in_joyhub_agreement_update_put(**params) + obj_log.info(f"更新协议响应: {resp}") + + return resp diff --git a/dulizhan/library/BusinessKw/JoyHub/AppVersionManage.py b/dulizhan/library/BusinessKw/JoyHub/AppVersionManage.py new file mode 100644 index 0000000..274c006 --- /dev/null +++ b/dulizhan/library/BusinessKw/JoyHub/AppVersionManage.py @@ -0,0 +1,202 @@ +import logging +import allure +from dulizhan.library.Dlizhan_interface import DlzhanInterface + +obj_log = logging.getLogger("logger") + + +class AppVersionManage(DlzhanInterface): + def __init__(self): + super().__init__() + + @allure.step("创建app版本号") + def kw_joyhub_appversion_create_post(self, store_name, version, download_url, is_on, status, id=0): + """ + 创建app版本号管理业务关键字 + :param id: 主键,新增为0 + :param store_name: 应用商店 + :param version: 版本号 + :param download_url: 商城下载地址 + :param is_on: 是否上架(1是,2否) + :param status: 状态 (1正常 2停用) + :return: 响应结果 + """ + obj_log.info(f"创建app版本号 - storeName: {store_name}, version: {version}, downloadUrl: {download_url}, isOn: {is_on}, status: {status}") + + params = { + "id": id, + "storeName": store_name, + "version": version, + "downloadUrl": download_url, + "isOn": is_on, + "status": status + } + + resp = self.kw_in_joyhub_appversion_create_post(**params) + obj_log.info(f"创建app版本号响应: {resp}") + + return resp + + @allure.step("删除app版本号") + def kw_joyhub_appversion_delete_delete(self, appversion_id): + """ + 删除app版本号管理业务关键字 + :param appversion_id: app版本号编号 + :return: 响应结果 + """ + obj_log.info(f"删除app版本号 - id: {appversion_id}") + + resp = self.kw_in_joyhub_appversion_delete_delete(appversion_id=appversion_id) + obj_log.info(f"删除app版本号响应: {resp}") + + return resp + + @allure.step("批量删除app版本号") + def kw_joyhub_appversion_delete_list_delete(self, appversion_ids): + """ + 批量删除app版本号管理业务关键字 + :param appversion_ids: app版本号编号列表 + :return: 响应结果 + """ + obj_log.info(f"批量删除app版本号 - ids: {appversion_ids}") + + resp = self.kw_in_joyhub_appversion_delete_list_delete(ids=appversion_ids) + obj_log.info(f"批量删除app版本号响应: {resp}") + + return resp + + @allure.step("导出app版本号Excel") + def kw_joyhub_appversion_export_excel_get(self, page_no=1, page_size=10, **kwargs): + """ + 导出app版本号管理 Excel业务关键字 + :param page_no: 页码 + :param page_size: 每页条数 + :param store_name: 应用商店 + :param version: 版本号 + :param download_url: 商城下载地址 + :param is_on: 是否上架 + :param status: 状态 + :return: 响应结果 + """ + obj_log.info(f"导出app版本号Excel - pageNo: {page_no}, pageSize: {page_size}") + + params = { + "pageNo": page_no, + "pageSize": page_size, + "storeName": kwargs.get("store_name", ""), + "version": kwargs.get("version", ""), + "downloadUrl": kwargs.get("download_url", ""), + "isOn": kwargs.get("is_on", ""), + "status": kwargs.get("status", "") + } + + resp = self.kw_in_joyhub_appversion_export_excel_get(**params) + obj_log.info(f"导出app版本号Excel响应: {resp}") + + return resp + + @allure.step("获得app版本号详情") + def kw_joyhub_appversion_get_get(self, appversion_id): + """ + 获得app版本号管理业务关键字 + :param appversion_id: app版本号编号 + :return: 响应结果 + """ + obj_log.info(f"获得app版本号详情 - id: {appversion_id}") + + resp = self.kw_in_joyhub_appversion_get_get(appversion_id=appversion_id) + obj_log.info(f"获得app版本号详情响应: {resp}") + + return resp + + @allure.step("获得导入app版本号模板") + def kw_joyhub_appversion_get_import_template_get(self): + """ + 获得导入app版本号管理模板业务关键字 + :return: 响应结果 + """ + obj_log.info("获得导入app版本号模板") + + resp = self.kw_in_joyhub_appversion_get_import_template_get() + obj_log.info(f"获得导入app版本号模板响应: {resp}") + + return resp + + @allure.step("导入app版本号Excel") + def kw_joyhub_appversion_import_excel_post(self, update_support, user_id=None): + """ + 导入app版本号管理Excel业务关键字 + :param update_support: 是否支持更新 + :param user_id: 创建人-为空则取当前人 + :return: 响应结果 + """ + obj_log.info(f"导入app版本号Excel - updateSupport: {update_support}, userId: {user_id}") + + params = { + "updateSupport": update_support + } + if user_id is not None: + params["userId"] = user_id + + resp = self.kw_in_joyhub_appversion_import_excel_post(**params) + obj_log.info(f"导入app版本号Excel响应: {resp}") + + return resp + + @allure.step("获得app版本号分页列表") + def kw_joyhub_appversion_page_get(self, page_no=1, page_size=10, **kwargs): + """ + 获得app版本号管理分页业务关键字 + :param page_no: 页码 + :param page_size: 每页条数 + :param store_name: 应用商店 + :param version: 版本号 + :param download_url: 商城下载地址 + :param is_on: 是否上架 + :param status: 状态 + :return: 响应结果 + """ + obj_log.info(f"获得app版本号分页列表 - pageNo: {page_no}, pageSize: {page_size}") + + params = { + "pageNo": page_no, + "pageSize": page_size, + "storeName": kwargs.get("store_name", ""), + "version": kwargs.get("version", ""), + "downloadUrl": kwargs.get("download_url", ""), + "isOn": kwargs.get("is_on", ""), + "status": kwargs.get("status", "") + } + + resp = self.kw_in_joyhub_appversion_page_get(**params) + obj_log.info(f"获得app版本号分页列表响应: {resp}") + + return resp + + @allure.step("更新app版本号") + def kw_joyhub_appversion_update_put(self, appversion_id, store_name, version, download_url, is_on, status): + """ + 更新app版本号管理业务关键字 + :param appversion_id: 主键 + :param store_name: 应用商店 + :param version: 版本号 + :param download_url: 商城下载地址 + :param is_on: 是否上架(1是,2否) + :param status: 状态 (1正常 2停用) + :return: 响应结果 + """ + obj_log.info(f"更新app版本号 - id: {appversion_id}, storeName: {store_name}, version: {version}, downloadUrl: {download_url}, isOn: {is_on}, status: {status}") + + params = { + "id": appversion_id, + "storeName": store_name, + "version": version, + "downloadUrl": download_url, + "isOn": is_on, + "status": status + } + + resp = self.kw_in_joyhub_appversion_update_put(**params) + obj_log.info(f"更新app版本号响应: {resp}") + + return resp diff --git a/dulizhan/library/Dlizhan_interface.py b/dulizhan/library/Dlizhan_interface.py index 12882a7..1fce889 100644 --- a/dulizhan/library/Dlizhan_interface.py +++ b/dulizhan/library/Dlizhan_interface.py @@ -39,7 +39,7 @@ class DlzhanInterface: def set_joyhub_token(self, token): self.token = token - def _joyhub_request(self, method, path, is_check='', note='', **kwargs): + def _joyhub_request(self, method, path, is_check='', note='', return_json=True, **kwargs): url = "{}{}".format(self.joyhub_domain, path) headers = self._get_joyhub_headers() obj_log.info("=========== {} ===========".format(note or path)) @@ -58,7 +58,11 @@ class DlzhanInterface: resp = req_map.get(method.upper(), lambda: None)() self._check_resp(is_check, resp) - return resp.json() + + if return_json: + return resp.json() + else: + return resp def _clear_user_fingerprint(self, username): try: @@ -251,7 +255,7 @@ class DlzhanInterface: return self._joyhub_request('DELETE', f'/admin-api/jh/banner/delete-list?ids={ids_str}', is_check, '批量删除Banner管理') def kw_in_joyhub_banner_get_import_template_get(self, is_check=''): - return self._joyhub_request('GET', '/admin-api/jh/banner/get-import-template', is_check, '获得导入Banner管理模板') + return self._joyhub_request('GET', '/admin-api/jh/banner/get-import-template', is_check, '获得导入Banner管理模板', return_json=False) def kw_in_joyhub_banner_get_get(self, banner_id, is_check=''): return self._joyhub_request('GET', f'/admin-api/jh/banner/get?id={banner_id}', is_check, '获得Banner管理详情') @@ -262,6 +266,35 @@ class DlzhanInterface: def kw_in_joyhub_banner_update_put(self, is_check='', **kwargs): return self._joyhub_request('PUT', '/admin-api/jh/banner/update', is_check, '更新Banner管理', **kwargs) + # ============ app版本号管理接口 ============ + def kw_in_joyhub_appversion_create_post(self, is_check='', **kwargs): + return self._joyhub_request('POST', '/admin-api/jh/appversion/create', is_check, '创建app版本号管理', **kwargs) + + def kw_in_joyhub_appversion_delete_delete(self, appversion_id, is_check=''): + return self._joyhub_request('DELETE', f'/admin-api/jh/appversion/delete?id={appversion_id}', is_check, '删除app版本号管理') + + def kw_in_joyhub_appversion_delete_list_delete(self, ids, is_check=''): + ids_str = ','.join(map(str, ids)) + return self._joyhub_request('DELETE', f'/admin-api/jh/appversion/delete-list?ids={ids_str}', is_check, '批量删除app版本号管理') + + def kw_in_joyhub_appversion_export_excel_get(self, is_check='', **kwargs): + return self._joyhub_request('GET', '/admin-api/jh/appversion/export-excel', is_check, '导出app版本号管理 Excel', return_json=False, **kwargs) + + def kw_in_joyhub_appversion_get_get(self, appversion_id, is_check=''): + return self._joyhub_request('GET', f'/admin-api/jh/appversion/get?id={appversion_id}', is_check, '获得app版本号管理') + + def kw_in_joyhub_appversion_get_import_template_get(self, is_check=''): + return self._joyhub_request('GET', '/admin-api/jh/appversion/get-import-template', is_check, '获得导入app版本号管理模板', return_json=False) + + def kw_in_joyhub_appversion_import_excel_post(self, is_check='', **kwargs): + return self._joyhub_request('POST', '/admin-api/jh/appversion/import-excel', is_check, '导入app版本号管理Excel', **kwargs) + + def kw_in_joyhub_appversion_page_get(self, is_check='', **kwargs): + return self._joyhub_request('GET', '/admin-api/jh/appversion/page', is_check, '获得app版本号管理分页', **kwargs) + + def kw_in_joyhub_appversion_update_put(self, is_check='', **kwargs): + return self._joyhub_request('PUT', '/admin-api/jh/appversion/update', is_check, '更新app版本号管理', **kwargs) + def kw_in_joyhub_user_create_post(self, is_check='', **kwargs): return self._joyhub_request('POST', '/admin-api/system/user/create', is_check, '创建用户', **kwargs) @@ -330,6 +363,29 @@ class DlzhanInterface: def kw_in_joyhub_dept_update_put(self, is_check='', **kwargs): return self._joyhub_request('PUT', '/admin-api/system/dept/update', is_check, '更新部门', **kwargs) + # ============ 协议管理接口 ============ + def kw_in_joyhub_agreement_create_post(self, is_check='', **kwargs): + return self._joyhub_request('POST', '/admin-api/jh/agreement/create', is_check, '创建协议', **kwargs) + + def kw_in_joyhub_agreement_delete_delete(self, agreement_id, is_check=''): + return self._joyhub_request('DELETE', f'/admin-api/jh/agreement/delete?id={agreement_id}', is_check, '删除协议') + + def kw_in_joyhub_agreement_delete_list_delete(self, ids, is_check=''): + ids_str = ','.join(map(str, ids)) + return self._joyhub_request('DELETE', f'/admin-api/jh/agreement/delete-list?ids={ids_str}', is_check, '批量删除协议') + + def kw_in_joyhub_agreement_export_excel_get(self, is_check='', **kwargs): + return self._joyhub_request('GET', '/admin-api/jh/agreement/export-excel', is_check, '导出协议 Excel', return_json=False, **kwargs) + + def kw_in_joyhub_agreement_get_get(self, agreement_id, is_check=''): + return self._joyhub_request('GET', f'/admin-api/jh/agreement/get?id={agreement_id}', is_check, '获得协议') + + def kw_in_joyhub_agreement_page_get(self, is_check='', **kwargs): + return self._joyhub_request('GET', '/admin-api/jh/agreement/page', is_check, '获得协议分页', **kwargs) + + def kw_in_joyhub_agreement_update_put(self, is_check='', **kwargs): + return self._joyhub_request('PUT', '/admin-api/jh/agreement/update', is_check, '更新协议', **kwargs) + if __name__ == '__main__': test = DlzhanInterface() diff --git a/dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_Agreement.py b/dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_Agreement.py new file mode 100644 index 0000000..2cb8690 --- /dev/null +++ b/dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_Agreement.py @@ -0,0 +1,299 @@ +import pytest +import allure +import logging +import requests +import json +import time +from dulizhan.library.BusinessKw.JoyHub.AgreementManage import AgreementManage + +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') + + +@allure.feature("管理后台 - 协议管理模块") +class TestAgreementManage: + agreement_id = None + token_set = False + + @classmethod + def setup_class(cls): + """在整个测试类开始时登录一次,所有测试用例共享token""" + logging.info("=============================================") + logging.info("=========== 开始登录,获取Token ============") + logging.info("=============================================") + + cls.test_case = AgreementManage() + 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("验证获得协议分页") + @allure.title("测试获得协议分页接口") + def test_joyhub_agreement_page_get(self): + """测试获得协议分页接口""" + with allure.step("1. 准备请求参数"): + params = { + "page_no": 1, + "page_size": 10, + "type": "", + "title": "", + "content": "", + "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_agreement_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("获得协议分页列表验证通过") + + @allure.story("验证创建协议") + @allure.title("测试创建协议接口") + def test_joyhub_agreement_create_post(self): + """测试创建协议接口""" + with allure.step("1. 准备请求参数"): + timestamp = int(time.time()) + params = { + "type": 1, + "title": f"测试协议_{timestamp}", + "content": f"这是测试协议内容_{timestamp}", + "terminal": "web", + "lang": "de", + "rank_num": timestamp % 1000, + "status": 2 + } + 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_agreement_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字段不是整数类型" + TestAgreementManage.agreement_id = resp["data"] + logging.info(f"创建协议成功,协议ID: {TestAgreementManage.agreement_id}") + + @allure.story("验证获得协议详情") + @allure.title("测试获得协议详情接口") + def test_joyhub_agreement_get_get(self): + """测试获得协议详情接口""" + with allure.step("1. 先创建一个协议"): + timestamp = int(time.time()) + create_resp = self.test_case.kw_joyhub_agreement_create_post( + type=2, + title=f"详情测试协议_{timestamp}", + content=f"详情测试协议内容_{timestamp}", + terminal="app", + lang="ja", + rank_num=(timestamp % 1000) + 1000, + status=1 + ) + agreement_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None + + if not agreement_id: + pytest.skip("创建测试协议失败,跳过详情测试") + + allure.attach(json.dumps({"id": agreement_id}, ensure_ascii=False), name="协议ID", attachment_type=allure.attachment_type.TEXT) + + with allure.step("2. 调用获得详情接口"): + resp = self.test_case.kw_joyhub_agreement_get_get(agreement_id=agreement_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"] == agreement_id, "返回的ID与请求的不一致" + logging.info("获得协议详情验证通过") + + @allure.story("验证更新协议") + @allure.title("测试更新协议接口") + def test_joyhub_agreement_update_put(self): + """测试更新协议接口""" + with allure.step("1. 先创建一个协议"): + timestamp = int(time.time()) + create_resp = self.test_case.kw_joyhub_agreement_create_post( + type=1, + title=f"待更新协议_{timestamp}", + content=f"待更新协议内容_{timestamp}", + terminal="app", + lang="de", + rank_num=(timestamp % 1000) + 2000, + status=1 + ) + agreement_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None + + if not agreement_id: + pytest.skip("创建测试协议失败,跳过更新测试") + + allure.attach(json.dumps({"id": agreement_id}, ensure_ascii=False), name="协议ID", attachment_type=allure.attachment_type.TEXT) + + with allure.step("2. 调用更新接口"): + timestamp = int(time.time()) + update_params = { + "agreement_id": agreement_id, + "type": 2, + "title": f"已更新协议_{timestamp}", + "content": f"已更新协议内容_{timestamp}", + "terminal": "web", + "lang": "ja", + "rank_num": (timestamp % 1000) + 3000, + "status": 2 + } + resp = self.test_case.kw_joyhub_agreement_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, "更新协议失败" + logging.info("更新协议验证通过") + + @allure.story("验证删除协议") + @allure.title("测试删除协议接口") + def test_joyhub_agreement_delete_delete(self): + """测试删除协议接口""" + with allure.step("1. 先创建一个测试协议"): + timestamp = int(time.time()) + create_resp = self.test_case.kw_joyhub_agreement_create_post( + type=1, + title=f"待删除协议_{timestamp}", + content=f"待删除协议内容_{timestamp}", + terminal="web", + lang="ja", + rank_num=(timestamp % 1000) + 4000, + status=2 + ) + agreement_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None + + if not agreement_id: + pytest.skip("创建测试协议失败,跳过删除测试") + + allure.attach(json.dumps({"id": agreement_id}, ensure_ascii=False), name="待删除协议ID", attachment_type=allure.attachment_type.TEXT) + + with allure.step("2. 调用删除接口"): + resp = self.test_case.kw_joyhub_agreement_delete_delete(agreement_id=agreement_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, "删除协议失败" + logging.info("删除协议验证通过") + + @allure.story("验证批量删除协议") + @allure.title("测试批量删除协议接口") + def test_joyhub_agreement_delete_list_delete(self): + """测试批量删除协议接口""" + with allure.step("1. 先创建两个测试协议"): + timestamp = int(time.time()) + resp1 = self.test_case.kw_joyhub_agreement_create_post( + type=2, + title=f"批量删除协议1_{timestamp}", + content=f"批量删除协议内容1_{timestamp}", + terminal="app", + lang="de", + rank_num=(timestamp % 1000) + 5000, + status=2 + ) + resp2 = self.test_case.kw_joyhub_agreement_create_post( + type=1, + title=f"批量删除协议2_{timestamp}", + content=f"批量删除协议内容2_{timestamp}", + terminal="app", + lang="ja", + rank_num=(timestamp % 1000) + 6000, + status=2 + ) + + agreement_id1 = resp1.get("data") if resp1 and resp1.get("code") == 0 else None + agreement_id2 = resp2.get("data") if resp2 and resp2.get("code") == 0 else None + + if not agreement_id1 or not agreement_id2: + pytest.skip("创建测试协议失败,跳过批量删除测试") + + agreement_ids = [agreement_id1, agreement_id2] + allure.attach(json.dumps({"ids": agreement_ids}, ensure_ascii=False), name="待删除协议IDs", attachment_type=allure.attachment_type.TEXT) + + with allure.step("2. 调用批量删除接口"): + resp = self.test_case.kw_joyhub_agreement_delete_list_delete(agreement_ids=agreement_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("批量删除协议验证通过") + + @allure.story("验证导出Excel") + @allure.title("测试导出协议Excel接口") + def test_joyhub_agreement_export_excel_get(self): + """测试导出协议Excel接口""" + with allure.step("1. 准备请求参数"): + params = { + "type": "", + "title": "", + "content": "", + "status": "" + } + allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT) + + with allure.step("2. 调用导出Excel接口"): + resp = self.test_case.kw_joyhub_agreement_export_excel_get(**params) + + with allure.step("3. 验证响应"): + assert resp is not None, "响应为空" + assert resp.status_code == 200, f"请求失败,status_code={resp.status_code}" + assert len(resp.content) > 0, "响应内容为空" + logging.info("导出协议Excel验证通过") diff --git a/dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_AppVersion.py b/dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_AppVersion.py new file mode 100644 index 0000000..8b82748 --- /dev/null +++ b/dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_AppVersion.py @@ -0,0 +1,302 @@ +import pytest +import allure +import logging +import requests +import json +import time +from dulizhan.library.BusinessKw.JoyHub.AppVersionManage import AppVersionManage + +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') + + +@allure.feature("管理后台 - app版本号管理模块") +class TestAppVersionManage: + appversion_id = None + token_set = False + + @classmethod + def setup_class(cls): + """在整个测试类开始时登录一次,所有测试用例共享token""" + logging.info("=============================================") + logging.info("=========== 开始登录,获取Token ============") + logging.info("=============================================") + + cls.test_case = AppVersionManage() + 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("验证获得app版本号分页") + @allure.title("测试获得app版本号管理分页接口") + def test_joyhub_appversion_page_get(self): + """测试获得app版本号管理分页接口""" + with allure.step("1. 准备请求参数"): + params = { + "page_no": 1, + "page_size": 10, + "store_name": "", + "version": "", + "download_url": "", + "is_on": "", + "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_appversion_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("获得app版本号分页列表验证通过") + + @allure.story("验证创建app版本号") + @allure.title("测试创建app版本号管理接口") + def test_joyhub_appversion_create_post(self): + """测试创建app版本号管理接口""" + with allure.step("1. 准备请求参数"): + timestamp = int(time.time()) + params = { + "store_name": "App Store", + "version": f"1.0.{timestamp % 1000}", + "download_url": "https://www.example.com/download", + "is_on": 1, + "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_appversion_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字段不是整数类型" + TestAppVersionManage.appversion_id = resp["data"] + logging.info(f"创建app版本号成功,app版本号ID: {TestAppVersionManage.appversion_id}") + + @allure.story("验证获得app版本号详情") + @allure.title("测试获得app版本号详情接口") + def test_joyhub_appversion_get_get(self): + """测试获得app版本号详情接口""" + with allure.step("1. 先创建一个app版本号"): + timestamp = int(time.time()) + create_resp = self.test_case.kw_joyhub_appversion_create_post( + store_name="Google Play", + version=f"2.0.{timestamp % 1000}", + download_url="https://www.example.com/download", + is_on=1, + status=1 + ) + appversion_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None + + if not appversion_id: + pytest.skip("创建测试app版本号失败,跳过详情测试") + + allure.attach(json.dumps({"id": appversion_id}, ensure_ascii=False), name="app版本号 ID", attachment_type=allure.attachment_type.TEXT) + + with allure.step("2. 调用获得详情接口"): + resp = self.test_case.kw_joyhub_appversion_get_get(appversion_id=appversion_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"] == appversion_id, "返回的ID与请求的不一致" + logging.info("获得app版本号详情验证通过") + + @allure.story("验证更新app版本号") + @allure.title("测试更新app版本号管理接口") + def test_joyhub_appversion_update_put(self): + """测试更新app版本号管理接口""" + with allure.step("1. 先创建一个app版本号"): + timestamp = int(time.time()) + create_resp = self.test_case.kw_joyhub_appversion_create_post( + store_name="Huawei Store", + version=f"3.0.{timestamp % 1000}", + download_url="https://www.example.com/download", + is_on=1, + status=1 + ) + appversion_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None + + if not appversion_id: + pytest.skip("创建测试app版本号失败,跳过更新测试") + + allure.attach(json.dumps({"id": appversion_id}, ensure_ascii=False), name="app版本号 ID", attachment_type=allure.attachment_type.TEXT) + + with allure.step("2. 调用更新接口"): + timestamp = int(time.time()) + update_params = { + "appversion_id": appversion_id, + "store_name": "Updated Store", + "version": f"4.0.{timestamp % 1000}", + "download_url": "https://www.updated-example.com/download", + "is_on": 2, + "status": 2 + } + resp = self.test_case.kw_joyhub_appversion_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, "更新app版本号失败" + logging.info("更新app版本号验证通过") + + @allure.story("验证删除app版本号") + @allure.title("测试删除app版本号管理接口") + def test_joyhub_appversion_delete_delete(self): + """测试删除app版本号管理接口""" + with allure.step("1. 先创建一个测试app版本号"): + timestamp = int(time.time()) + create_resp = self.test_case.kw_joyhub_appversion_create_post( + store_name="Test Store", + version=f"5.0.{timestamp % 1000}", + download_url="https://www.example.com/download", + is_on=1, + status=2 + ) + appversion_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None + + if not appversion_id: + pytest.skip("创建测试app版本号失败,跳过删除测试") + + allure.attach(json.dumps({"id": appversion_id}, ensure_ascii=False), name="待删除app版本号 ID", attachment_type=allure.attachment_type.TEXT) + + with allure.step("2. 调用删除接口"): + resp = self.test_case.kw_joyhub_appversion_delete_delete(appversion_id=appversion_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, "删除app版本号失败" + logging.info("删除app版本号验证通过") + + @allure.story("验证批量删除app版本号") + @allure.title("测试批量删除app版本号管理接口") + def test_joyhub_appversion_delete_list_delete(self): + """测试批量删除app版本号管理接口""" + with allure.step("1. 先创建两个测试app版本号"): + timestamp = int(time.time()) + resp1 = self.test_case.kw_joyhub_appversion_create_post( + store_name="Batch Store 1", + version=f"6.0.{timestamp % 1000}", + download_url="https://www.example.com/download", + is_on=1, + status=2 + ) + resp2 = self.test_case.kw_joyhub_appversion_create_post( + store_name="Batch Store 2", + version=f"7.0.{timestamp % 1000 + 1}", + download_url="https://www.example.com/download", + is_on=1, + status=2 + ) + + appversion_id1 = resp1.get("data") if resp1 and resp1.get("code") == 0 else None + appversion_id2 = resp2.get("data") if resp2 and resp2.get("code") == 0 else None + + if not appversion_id1 or not appversion_id2: + pytest.skip("创建测试app版本号失败,跳过批量删除测试") + + appversion_ids = [appversion_id1, appversion_id2] + allure.attach(json.dumps({"ids": appversion_ids}, ensure_ascii=False), name="待删除app版本号 IDs", attachment_type=allure.attachment_type.TEXT) + + with allure.step("2. 调用批量删除接口"): + resp = self.test_case.kw_joyhub_appversion_delete_list_delete(appversion_ids=appversion_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, "批量删除app版本号失败" + logging.info("批量删除app版本号验证通过") + + @allure.story("验证获得导入模板") + @allure.title("测试获得导入app版本号管理模板接口") + def test_joyhub_appversion_get_import_template_get(self): + """测试获得导入app版本号管理模板接口""" + with allure.step("1. 调用获得导入模板接口"): + resp = self.test_case.kw_joyhub_appversion_get_import_template_get() + + with allure.step("2. 验证响应"): + assert resp is not None, "响应为空" + assert resp.status_code == 200, f"请求失败,status_code={resp.status_code}" + assert len(resp.content) > 0, "响应内容为空" + logging.info("获得导入app版本号模板验证通过") + + @allure.story("验证导出Excel") + @allure.title("测试导出app版本号管理Excel接口") + def test_joyhub_appversion_export_excel_get(self): + """测试导出app版本号管理Excel接口""" + with allure.step("1. 准备请求参数"): + params = { + "page_no": 1, + "page_size": 10, + "store_name": "", + "version": "", + "download_url": "", + "is_on": "", + "status": "" + } + allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT) + + with allure.step("2. 调用导出Excel接口"): + resp = self.test_case.kw_joyhub_appversion_export_excel_get(**params) + + with allure.step("3. 验证响应"): + assert resp is not None, "响应为空" + assert resp.status_code == 200, f"请求失败,status_code={resp.status_code}" + assert len(resp.content) > 0, "响应内容为空" + logging.info("导出app版本号Excel验证通过")