import pytest import allure import logging import requests import json import time from dulizhan.library.BusinessKw.JoyHub.AfterSalesPolicyManage import AfterSalesPolicyManage logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') @allure.feature("管理后台 - 售后政策管理模块") class TestAfterSalesPolicyManage: policy_id = None token_set = False @classmethod def setup_class(cls): """在整个测试类开始时登录一次,所有测试用例共享token""" logging.info("=============================================") logging.info("=========== 开始登录,获取Token ============") logging.info("=============================================") cls.test_case = AfterSalesPolicyManage() 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_after_sales_policy_page_get(self): """测试获得售后政策分页接口""" with allure.step("1. 准备请求参数"): params = { "page_no": 1, "page_size": 10, "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_after_sales_policy_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_after_sales_policy_create_and_update(self): """测试创建和更新售后政策接口""" with allure.step("1. 先创建一个新品牌供售后政策使用"): timestamp = int(time.time()) create_brand_resp = self.test_case.kw_joyhub_after_sales_brand_create_post( brand_name=f"测试品牌_售后政策_{timestamp}", after_sales_policy_id=0, status=1 ) if create_brand_resp and create_brand_resp.get("code") == 0: brand_id = create_brand_resp.get("data") logging.info(f"创建测试品牌成功,品牌ID: {brand_id}") else: pytest.skip(f"创建测试品牌失败: {create_brand_resp}") allure.attach(json.dumps({"brand_id": brand_id}, ensure_ascii=False), name="品牌ID", attachment_type=allure.attachment_type.TEXT) with allure.step("2. 准备创建请求参数"): params = { "title": f"测试售后政策_{timestamp}", "content": f"这是测试售后政策内容_{timestamp}", "lang": "de", "brand_id": brand_id, "status": 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_after_sales_policy_create_post(**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 isinstance(resp["data"], int), "data字段不是整数类型" policy_id = resp["data"] TestAfterSalesPolicyManage.policy_id = policy_id logging.info(f"创建售后政策成功,售后政策ID: {policy_id}") with allure.step("5. 调用更新接口"): update_timestamp = int(time.time()) update_params = { "policy_id": policy_id, "title": f"已更新售后政策_{update_timestamp}", "content": f"已更新售后政策内容_{update_timestamp}", "lang": "ja", "brand_id": brand_id, "status": 2 } allure.attach(json.dumps(update_params, ensure_ascii=False), name="更新请求参数", attachment_type=allure.attachment_type.TEXT) update_resp = self.test_case.kw_joyhub_after_sales_policy_update_put(**update_params) allure.attach(json.dumps(update_resp, ensure_ascii=False, indent=2), name="更新响应数据", attachment_type=allure.attachment_type.JSON) with allure.step("6. 验证更新响应"): assert update_resp is not None, "响应为空" assert "code" in update_resp, "响应中缺少code字段" assert update_resp["code"] == 0, f"请求失败,code={update_resp.get('code')}" assert "data" in update_resp, "响应中缺少data字段" assert update_resp["data"] is True, "更新售后政策失败" logging.info("更新售后政策验证通过") @allure.story("验证获得售后政策详情") @allure.title("测试获得售后政策详情接口") def test_joyhub_after_sales_policy_get_get(self): """测试获得售后政策详情接口""" with allure.step("1. 先创建一个售后政策"): timestamp = int(time.time()) create_resp = self.test_case.kw_joyhub_after_sales_policy_create_post( title=f"详情测试售后政策_{timestamp}", content=f"详情测试售后政策内容_{timestamp}", lang="ja", brand_id=12, status=2 ) policy_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None if not policy_id: pytest.skip("创建测试售后政策失败,跳过详情测试") allure.attach(json.dumps({"id": policy_id}, ensure_ascii=False), name="售后政策ID", attachment_type=allure.attachment_type.TEXT) with allure.step("2. 调用获得详情接口"): resp = self.test_case.kw_joyhub_after_sales_policy_get_get(policy_id=policy_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"] == policy_id, "返回的ID与请求的不一致" logging.info("获得售后政策详情验证通过") @allure.story("验证删除售后政策") @allure.title("测试删除售后政策接口") def test_joyhub_after_sales_policy_delete_delete(self): """测试删除售后政策接口""" with allure.step("1. 先创建一个测试售后政策"): timestamp = int(time.time()) create_resp = self.test_case.kw_joyhub_after_sales_policy_create_post( title=f"待删除售后政策_{timestamp}", content=f"待删除售后政策内容_{timestamp}", lang="en", brand_id=12, status=2 ) policy_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None if not policy_id: pytest.skip("创建测试售后政策失败,跳过删除测试") allure.attach(json.dumps({"id": policy_id}, ensure_ascii=False), name="待删除售后政策ID", attachment_type=allure.attachment_type.TEXT) with allure.step("2. 调用删除接口"): resp = self.test_case.kw_joyhub_after_sales_policy_delete_delete(policy_id=policy_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_after_sales_policy_delete_list_delete(self): """测试批量删除售后政策接口""" with allure.step("1. 先创建两个测试售后政策"): timestamp = int(time.time()) resp1 = self.test_case.kw_joyhub_after_sales_policy_create_post( title=f"批量删除售后政策1_{timestamp}", content=f"批量删除售后政策内容1_{timestamp}", lang="de", brand_id=12, status=2 ) resp2 = self.test_case.kw_joyhub_after_sales_policy_create_post( title=f"批量删除售后政策2_{timestamp}", content=f"批量删除售后政策内容2_{timestamp}", lang="ja", brand_id=12, status=2 ) policy_id1 = resp1.get("data") if resp1 and resp1.get("code") == 0 else None policy_id2 = resp2.get("data") if resp2 and resp2.get("code") == 0 else None if not policy_id1 or not policy_id2: pytest.skip("创建测试售后政策失败,跳过批量删除测试") policy_ids = [policy_id1, policy_id2] allure.attach(json.dumps({"ids": policy_ids}, ensure_ascii=False), name="待删除售后政策IDs", attachment_type=allure.attachment_type.TEXT) with allure.step("2. 调用批量删除接口"): resp = self.test_case.kw_joyhub_after_sales_policy_delete_list_delete(policy_ids=policy_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.feature("管理后台 - 售后政策-品牌管理模块") class TestAfterSalesBrandManage: brand_id = None policy_id = None token_set = False @classmethod def setup_class(cls): """在整个测试类开始时登录一次,所有测试用例共享token""" logging.info("=============================================") logging.info("=========== 开始登录,获取Token ============") logging.info("=============================================") cls.test_case = AfterSalesPolicyManage() 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))) # 创建一个售后政策供品牌测试使用 if cls.token_set: timestamp = int(time.time()) # 先创建一个新品牌,确保没有活跃的售后政策 create_brand_resp = cls.test_case.kw_joyhub_after_sales_brand_create_post( brand_name=f"品牌测试专用_{timestamp}", after_sales_policy_id=0, status=1 ) if create_brand_resp and create_brand_resp.get("code") == 0: brand_id = create_brand_resp.get("data") logging.info(f"创建测试品牌成功,品牌ID: {brand_id}") # 使用新创建的品牌创建售后政策 create_resp = cls.test_case.kw_joyhub_after_sales_policy_create_post( title=f"品牌测试售后政策_{timestamp}", content=f"品牌测试售后政策内容_{timestamp}", lang="en", brand_id=brand_id, status=1 ) if create_resp and create_resp.get("code") == 0: cls.policy_id = create_resp.get("data") logging.info(f"创建测试售后政策成功,ID: {cls.policy_id}") else: logging.warning(f"创建售后政策失败: {create_resp}") else: logging.warning(f"创建测试品牌失败: {create_brand_resp}") @allure.story("验证获得售后政策-品牌分页") @allure.title("测试获得售后政策-品牌分页接口") def test_joyhub_after_sales_brand_page_get(self): """测试获得售后政策-品牌分页接口""" with allure.step("1. 准备请求参数"): params = { "page_no": 1, "page_size": 10, "brand_name": "", "after_sales_policy_id": "", "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_after_sales_brand_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_after_sales_brand_create_post(self): """测试创建售后政策-品牌接口""" if not self.policy_id: pytest.skip("未创建测试售后政策,跳过品牌创建测试") with allure.step("1. 准备请求参数"): timestamp = int(time.time()) params = { "brand_name": f"测试品牌_{timestamp}", "after_sales_policy_id": self.policy_id, "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_after_sales_brand_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字段不是整数类型" TestAfterSalesBrandManage.brand_id = resp["data"] logging.info(f"创建售后政策-品牌成功,品牌ID: {TestAfterSalesBrandManage.brand_id}") @allure.story("验证获得售后政策-品牌详情") @allure.title("测试获得售后政策-品牌详情接口") def test_joyhub_after_sales_brand_get_get(self): """测试获得售后政策-品牌详情接口""" if not self.policy_id: pytest.skip("未创建测试售后政策,跳过品牌详情测试") with allure.step("1. 先创建一个售后政策-品牌"): timestamp = int(time.time()) create_resp = self.test_case.kw_joyhub_after_sales_brand_create_post( brand_name=f"详情测试品牌_{timestamp}", after_sales_policy_id=self.policy_id, status=2 ) brand_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None if not brand_id: pytest.skip("创建测试品牌失败,跳过详情测试") allure.attach(json.dumps({"id": brand_id}, ensure_ascii=False), name="售后政策-品牌ID", attachment_type=allure.attachment_type.TEXT) with allure.step("2. 调用获得详情接口"): resp = self.test_case.kw_joyhub_after_sales_brand_get_get(brand_id=brand_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"] == brand_id, "返回的ID与请求的不一致" logging.info("获得售后政策-品牌详情验证通过") @allure.story("验证更新售后政策-品牌") @allure.title("测试更新售后政策-品牌接口") def test_joyhub_after_sales_brand_update_put(self): """测试更新售后政策-品牌接口""" if not self.policy_id: pytest.skip("未创建测试售后政策,跳过品牌更新测试") with allure.step("1. 先创建一个售后政策-品牌"): timestamp = int(time.time()) create_resp = self.test_case.kw_joyhub_after_sales_brand_create_post( brand_name=f"待更新品牌_{timestamp}", after_sales_policy_id=self.policy_id, status=1 ) brand_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None if not brand_id: pytest.skip("创建测试品牌失败,跳过更新测试") allure.attach(json.dumps({"id": brand_id}, ensure_ascii=False), name="售后政策-品牌ID", attachment_type=allure.attachment_type.TEXT) with allure.step("2. 调用更新接口"): timestamp = int(time.time()) update_params = { "brand_id": brand_id, "brand_name": f"已更新品牌_{timestamp}", "after_sales_policy_id": self.policy_id, "status": 2 } resp = self.test_case.kw_joyhub_after_sales_brand_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_after_sales_brand_delete_delete(self): """测试删除售后政策-品牌接口""" if not self.policy_id: pytest.skip("未创建测试售后政策,跳过品牌删除测试") with allure.step("1. 先创建一个测试售后政策-品牌"): timestamp = int(time.time()) create_resp = self.test_case.kw_joyhub_after_sales_brand_create_post( brand_name=f"待删除品牌_{timestamp}", after_sales_policy_id=self.policy_id, status=2 ) brand_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None if not brand_id: pytest.skip("创建测试品牌失败,跳过删除测试") allure.attach(json.dumps({"id": brand_id}, ensure_ascii=False), name="待删除品牌ID", attachment_type=allure.attachment_type.TEXT) with allure.step("2. 调用删除接口"): resp = self.test_case.kw_joyhub_after_sales_brand_delete_delete(brand_id=brand_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_after_sales_brand_delete_list_delete(self): """测试批量删除售后政策-品牌接口""" if not self.policy_id: pytest.skip("未创建测试售后政策,跳过批量删除品牌测试") with allure.step("1. 先创建两个测试售后政策-品牌"): timestamp = int(time.time()) resp1 = self.test_case.kw_joyhub_after_sales_brand_create_post( brand_name=f"批量删除品牌1_{timestamp}", after_sales_policy_id=self.policy_id, status=2 ) resp2 = self.test_case.kw_joyhub_after_sales_brand_create_post( brand_name=f"批量删除品牌2_{timestamp}", after_sales_policy_id=self.policy_id, status=2 ) brand_id1 = resp1.get("data") if resp1 and resp1.get("code") == 0 else None brand_id2 = resp2.get("data") if resp2 and resp2.get("code") == 0 else None if not brand_id1 or not brand_id2: pytest.skip("创建测试品牌失败,跳过批量删除测试") brand_ids = [brand_id1, brand_id2] allure.attach(json.dumps({"ids": brand_ids}, ensure_ascii=False), name="待删除品牌IDs", attachment_type=allure.attachment_type.TEXT) with allure.step("2. 调用批量删除接口"): resp = self.test_case.kw_joyhub_after_sales_brand_delete_list_delete(brand_ids=brand_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("验证获得可用的品牌列表") @allure.title("测试获得可用的品牌列表接口") def test_joyhub_after_sales_brand_list_available_get(self): """测试获得可用的品牌列表接口""" with allure.step("1. 调用接口"): resp = self.test_case.kw_joyhub_after_sales_brand_list_available_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("获得可用的品牌列表验证通过")