""" 一物一码会员营销系统 - API 业务流程测试 直接测试后端API,不依赖前端UI """ import requests import json import time from datetime import datetime, timedelta from typing import Optional, Dict, Any class APITester: def __init__(self, base_url: str = "http://localhost:5511"): self.base_url = base_url self.admin_token: Optional[str] = None self.member_token: Optional[str] = None self.test_results = [] self.marketing_codes = [] self.gift_id: Optional[str] = None self.member_id: Optional[str] = None self.order_id: Optional[str] = None def log_test(self, test_name: str, status: str, message: str = "", data: Any = None): """记录测试结果""" result = { "test": test_name, "status": status, "message": message, "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "data": data } self.test_results.append(result) status_emoji = "✅" if status == "PASS" else "❌" if status == "FAIL" else "⏭️" print(f"{status_emoji} [{test_name}] {status}: {message}") if data: print(f" 数据: {json.dumps(data, ensure_ascii=False, indent=2)}") def request(self, method: str, endpoint: str, **kwargs) -> Optional[Dict]: """发送HTTP请求""" url = f"{self.base_url}{endpoint}" headers = kwargs.get('headers', {}) # 添加认证头 if 'admin' in endpoint and self.admin_token: headers['Authorization'] = f'Bearer {self.admin_token}' elif 'members' in endpoint and self.member_token: headers['Authorization'] = f'Bearer {self.member_token}' kwargs['headers'] = headers try: response = requests.request(method, url, **kwargs) if response.status_code >= 400: print(f" HTTP {response.status_code}: {response.text}") return None return response.json() if response.text else {} except Exception as e: print(f" 请求失败: {e}") return None def test_health_check(self): """测试健康检查""" print("\n=== 测试:健康检查 ===") response = self.request('GET', '/health') if response: self.log_test("健康检查", "PASS", "后端服务正常") return True else: self.log_test("健康检查", "FAIL", "后端服务不可用") return False def test_generate_marketing_codes(self): """测试生成营销码""" print("\n=== 测试:生成营销码 ===") batch_no = f"BATCH-{int(time.time())}" product_id = "PROD-001" payload = { "batchNo": batch_no, "productId": product_id, "productName": "测试产品A", "quantity": 10, "expirationTime": (datetime.now() + timedelta(days=30)).isoformat() } response = self.request('POST', '/api/admin/marketing-codes/generate', json=payload) if response and response.get('success'): data = response.get('data', {}) self.marketing_codes = data.get('marketingCodes', []) self.log_test("生成营销码", "PASS", f"成功生成 {len(self.marketing_codes)} 个营销码", {"批次号": batch_no, "数量": len(self.marketing_codes)}) return True else: self.log_test("生成营销码", "FAIL", "生成失败") return False def test_create_points_rule(self): """测试创建积分规则""" print("\n=== 测试:创建积分规则 ===") payload = { "ruleName": "测试产品积分规则", "ruleType": 1, # Product "pointsValue": 100, "rewardMultiplier": 1.0, "productId": "PROD-001", "startTime": datetime.now().isoformat(), "endTime": (datetime.now() + timedelta(days=365)).isoformat() } response = self.request('POST', '/api/admin/points-rules', json=payload) if response and response.get('success'): self.log_test("创建积分规则", "PASS", "积分规则创建成功", {"规则名": payload['ruleName'], "积分值": payload['pointsValue']}) return True else: self.log_test("创建积分规则", "FAIL", "创建失败") return False def test_create_gift(self): """测试创建礼品""" print("\n=== 测试:创建礼品 ===") payload = { "name": "测试礼品-电子产品", "giftType": 1, # Physical "description": "这是一个测试用的电子产品礼品", "imageUrl": "https://via.placeholder.com/400", "requiredPoints": 500, "totalStock": 100, "redemptionLimit": 2 } response = self.request('POST', '/api/admin/gifts', json=payload) if response and response.get('success'): data = response.get('data', {}) self.gift_id = data.get('giftId') self.log_test("创建礼品", "PASS", "礼品创建成功", {"礼品ID": self.gift_id, "名称": payload['name']}) return True else: self.log_test("创建礼品", "FAIL", "创建失败") return False def test_put_gift_on_shelf(self): """测试礼品上架""" print("\n=== 测试:礼品上架 ===") if not self.gift_id: self.log_test("礼品上架", "SKIP", "没有礼品ID") return False response = self.request('POST', f'/api/admin/gifts/{self.gift_id}/putonshelf') if response and response.get('success'): self.log_test("礼品上架", "PASS", "礼品上架成功") return True else: self.log_test("礼品上架", "FAIL", "上架失败") return False def test_member_register(self): """测试会员注册""" print("\n=== 测试:会员注册 ===") timestamp = int(time.time()) % 100000000 phone = f"138{timestamp}" payload = { "phoneNumber": phone, "password": "123456", "nickname": f"测试用户{timestamp}" } response = self.request('POST', '/api/members/register', json=payload) if response and response.get('success'): data = response.get('data', {}) self.member_id = data.get('memberId') self.member_token = data.get('token') self.log_test("会员注册", "PASS", "会员注册成功", {"会员ID": self.member_id, "手机号": phone}) return True else: self.log_test("会员注册", "FAIL", "注册失败") return False def test_member_login(self): """测试会员登录""" print("\n=== 测试:会员登录 ===") # 如果已经注册过,跳过 if self.member_token: self.log_test("会员登录", "SKIP", "已有Token") return True self.log_test("会员登录", "SKIP", "需要先注册") return False def test_scan_marketing_code(self): """测试扫码获取积分""" print("\n=== 测试:扫码获取积分 ===") if not self.marketing_codes: self.log_test("扫码获取积分", "SKIP", "没有可用的营销码") return False marketing_code = self.marketing_codes[0] payload = { "marketingCode": marketing_code } response = self.request('POST', '/api/members/scan', json=payload) if response and response.get('success'): data = response.get('data', {}) points = data.get('pointsAwarded', 0) self.log_test("扫码获取积分", "PASS", f"成功获得 {points} 积分", {"营销码": marketing_code, "积分": points}) return True else: self.log_test("扫码获取积分", "FAIL", "扫码失败") return False def test_duplicate_scan(self): """测试重复扫码(验证唯一性)""" print("\n=== 测试:重复扫码验证 ===") if not self.marketing_codes: self.log_test("重复扫码验证", "SKIP", "没有可用的营销码") return False marketing_code = self.marketing_codes[0] payload = { "marketingCode": marketing_code } response = self.request('POST', '/api/members/scan', json=payload) # 应该失败 if response and not response.get('success'): self.log_test("重复扫码验证", "PASS", "正确阻止重复扫码", {"消息": response.get('message')}) return True else: self.log_test("重复扫码验证", "FAIL", "未能阻止重复扫码") return False def test_get_member_points(self): """测试查询会员积分""" print("\n=== 测试:查询会员积分 ===") if not self.member_id: self.log_test("查询会员积分", "SKIP", "没有会员ID") return False response = self.request('GET', f'/api/members/{self.member_id}') if response and response.get('success'): data = response.get('data', {}) points = data.get('availablePoints', 0) self.log_test("查询会员积分", "PASS", f"当前积分: {points}", {"会员ID": self.member_id, "积分": points}) return True else: self.log_test("查询会员积分", "FAIL", "查询失败") return False def test_get_gifts_list(self): """测试获取礼品列表""" print("\n=== 测试:获取礼品列表 ===") response = self.request('GET', '/api/gifts') if response and response.get('success'): data = response.get('data', []) on_shelf = [g for g in data if g.get('isOnShelf')] self.log_test("获取礼品列表", "PASS", f"共 {len(data)} 个礼品,{len(on_shelf)} 个已上架", {"总数": len(data), "上架": len(on_shelf)}) return True else: self.log_test("获取礼品列表", "FAIL", "查询失败") return False def test_redeem_gift(self): """测试兑换礼品""" print("\n=== 测试:兑换礼品 ===") if not self.gift_id: self.log_test("兑换礼品", "SKIP", "没有礼品ID") return False payload = { "giftId": self.gift_id, "quantity": 1, "deliveryAddress": { "consignee": "张三", "phoneNumber": "13800138000", "address": "北京市朝阳区xxx街道xxx号" } } response = self.request('POST', '/api/members/redeem', json=payload) if response and response.get('success'): data = response.get('data', {}) self.order_id = data.get('orderId') self.log_test("兑换礼品", "PASS", "礼品兑换成功", {"订单ID": self.order_id}) return True else: message = response.get('message', '兑换失败') if response else '兑换失败' self.log_test("兑换礼品", "FAIL", message) return False def test_get_member_orders(self): """测试查询会员订单""" print("\n=== 测试:查询会员订单 ===") response = self.request('GET', '/api/members/orders') if response and response.get('success'): data = response.get('data', []) self.log_test("查询会员订单", "PASS", f"共 {len(data)} 个订单", {"订单数": len(data)}) return True else: self.log_test("查询会员订单", "FAIL", "查询失败") return False def test_admin_get_orders(self): """测试管理员查询订单""" print("\n=== 测试:管理员查询订单 ===") response = self.request('GET', '/api/admin/redemption-orders') if response and response.get('success'): data = response.get('data', []) pending = [o for o in data if o.get('status') == 1] self.log_test("管理员查询订单", "PASS", f"共 {len(data)} 个订单,{len(pending)} 个待处理", {"总数": len(data), "待处理": len(pending)}) return True else: self.log_test("管理员查询订单", "FAIL", "查询失败") return False def test_dispatch_order(self): """测试订单发货""" print("\n=== 测试:订单发货 ===") if not self.order_id: self.log_test("订单发货", "SKIP", "没有订单ID") return False payload = { "trackingNumber": "SF1234567890" } response = self.request('POST', f'/api/admin/redemption-orders/{self.order_id}/dispatch', json=payload) if response and response.get('success'): self.log_test("订单发货", "PASS", "订单发货成功", {"物流单号": payload['trackingNumber']}) return True else: self.log_test("订单发货", "FAIL", "发货失败") return False def generate_report(self): """生成测试报告""" print("\n" + "="*60) print("API 测试报告") print("="*60) total = len(self.test_results) passed = sum(1 for r in self.test_results if r['status'] == 'PASS') failed = sum(1 for r in self.test_results if r['status'] == 'FAIL') skipped = sum(1 for r in self.test_results if r['status'] == 'SKIP') print(f"\n总测试数: {total}") print(f"通过: {passed} ✅") print(f"失败: {failed} ❌") print(f"跳过: {skipped} ⏭️") if total > 0: print(f"成功率: {(passed/total*100):.2f}%") print("\n详细结果:") print("-"*60) for result in self.test_results: status_emoji = "✅" if result['status'] == 'PASS' else "❌" if result['status'] == 'FAIL' else "⏭️" print(f"{status_emoji} {result['test']}: {result['message']}") # 保存JSON报告 with open('test_api_report.json', 'w', encoding='utf-8') as f: json.dump(self.test_results, f, ensure_ascii=False, indent=2) print(f"\n测试报告已保存到: test_api_report.json") # 返回是否有失败 return failed == 0 def run_api_tests(): """运行所有API测试""" print("="*60) print("一物一码会员营销系统 - API 业务流程测试") print("="*60) tester = APITester() # 1. 健康检查 if not tester.test_health_check(): print("\n❌ 后端服务不可用,测试终止") return False # 2. 管理后台功能测试 print("\n【测试管理后台功能】") tester.test_generate_marketing_codes() tester.test_create_points_rule() tester.test_create_gift() tester.test_put_gift_on_shelf() # 3. 会员功能测试 print("\n【测试会员功能】") if tester.test_member_register(): tester.test_scan_marketing_code() tester.test_duplicate_scan() # 验证唯一性 tester.test_get_member_points() # 4. 积分商城测试 print("\n【测试积分商城】") tester.test_get_gifts_list() tester.test_redeem_gift() # 可能因积分不足失败 tester.test_get_member_orders() # 5. 订单管理测试 print("\n【测试订单管理】") tester.test_admin_get_orders() tester.test_dispatch_order() # 生成报告 success = tester.generate_report() return success if __name__ == "__main__": success = run_api_tests() exit(0 if success else 1)