""" E2E关键业务流程测试套件 测试范围: 1. 用户管理完整生命周期流程 2. 角色权限管理流程 3. 菜单权限配置流程 4. 文件上传下载流程 5. 审计日志记录流程 作者: 张翔 日期: 2026-04-01 """ import pytest import asyncio import time import uuid from typing import Dict, Any from api.auth_api import AuthAPI from api.user_api import UserAPI from api.role_api import RoleAPI from api.menu_api import MenuAPI from api.file_api import FileAPI from api.audit_api import AuditAPI from config.settings import settings @pytest.mark.e2e @pytest.mark.critical @pytest.mark.asyncio class TestE2ECriticalWorkflows: """E2E关键业务流程测试类""" async def test_e2e_user_lifecycle_workflow( self, authenticated_client, test_data_manager ): """ E2E-01: 用户管理完整生命周期流程 测试场景: 1. 创建新用户 2. 分配角色 3. 用户登录验证 4. 权限验证 5. 用户信息更新 6. 用户禁用 7. 用户删除 """ user_api = UserAPI(authenticated_client) role_api = RoleAPI(authenticated_client) auth_api = AuthAPI(authenticated_client) unique_id = f"e2e_{int(time.time() * 1000)}_{uuid.uuid4().hex[:8]}" # 步骤1: 创建测试角色 role_data = { "roleName": f"E2E_Test_Role_{unique_id}", "roleKey": f"e2e_test_role_{unique_id}", "roleSort": 1, "status": 1, "remark": "E2E测试角色" } role_response = await role_api.create_role(role_data) assert role_response.status_code == 201, "创建角色失败" role_id = role_response.json()["id"] test_data_manager.add_role(role_id) # 步骤2: 创建新用户 user_data = { "username": f"e2e_user_{unique_id}", "password": "Test123!@#", "email": f"e2e_user_{unique_id}@test.com", "nickname": "E2E测试用户", "phone": "13800138000", "status": 1, "roleId": role_id } user_response = await user_api.create_user(user_data) assert user_response.status_code == 201, "创建用户失败" user_id = user_response.json()["id"] test_data_manager.add_user(user_id) # 步骤3: 用户登录验证 login_response = await auth_api.login(user_data["username"], user_data["password"]) assert login_response.status_code == 200, "用户登录失败" token = login_response.json().get("token") assert token is not None, "未获取到登录Token" # 步骤4: 验证用户信息 user_info_response = await user_api.get_user_by_id(user_id) assert user_info_response.status_code == 200, "获取用户信息失败" user_info = user_info_response.json() assert user_info["username"] == user_data["username"], "用户名不匹配" assert user_info["email"] == user_data["email"], "邮箱不匹配" # 步骤5: 更新用户信息(使用后端支持的字段) update_data = { "email": f"updated_{unique_id}@example.com", "status": 1 } update_response = await user_api.update_user(user_id, update_data) assert update_response.status_code == 200, "更新用户信息失败" # 步骤6: 验证更新结果 updated_user_response = await user_api.get_user_by_id(user_id) updated_user = updated_user_response.json() assert updated_user["email"] == update_data["email"], "邮箱更新失败" # 步骤7: 禁用用户 disable_response = await user_api.update_user(user_id, {"status": 0}) assert disable_response.status_code == 200, "禁用用户失败" # 步骤8: 验证用户已被禁用 disabled_user_response = await user_api.get_user_by_id(user_id) disabled_user = disabled_user_response.json() assert disabled_user["status"] == 0, "用户状态未更新为禁用" # 步骤9: 删除用户 delete_response = await user_api.delete_user(user_id) assert delete_response.status_code in [200, 204], "删除用户失败" # 步骤10: 验证用户已被删除 verify_delete_response = await user_api.get_user_by_id(user_id) assert verify_delete_response.status_code == 404, "用户未正确删除" async def test_e2e_role_permission_workflow( self, authenticated_client, test_data_manager ): """ E2E-02: 角色权限管理流程 测试场景: 1. 创建角色 2. 分配菜单权限 3. 创建用户并分配角色 4. 验证用户权限 5. 修改角色权限 6. 验证权限即时生效 7. 删除角色 """ role_api = RoleAPI(authenticated_client) user_api = UserAPI(authenticated_client) menu_api = MenuAPI(authenticated_client) unique_id = f"{int(time.time() * 1000)}_{uuid.uuid4().hex[:8]}" # 步骤1: 创建角色 role_data = { "roleName": f"E2E_Role_{unique_id}", "roleKey": f"e2e_role_{unique_id}", "roleSort": 1, "status": 1 } role_response = await role_api.create_role(role_data) assert role_response.status_code == 201, "创建角色失败" role_id = role_response.json()["id"] test_data_manager.add_role(role_id) # 步骤2: 获取菜单列表 menus_response = await menu_api.get_menu_list() assert menus_response.status_code == 200, "获取菜单列表失败" menus = menus_response.json() assert len(menus) > 0, "菜单列表为空" # 步骤3: 分配菜单权限给角色 menu_ids = [menu["id"] for menu in menus[:3]] # 选择前3个菜单 assign_response = await role_api.assign_menus(role_id, menu_ids) assert assign_response.status_code == 200, "分配菜单权限失败" # 步骤4: 创建用户并分配角色 user_data = { "username": f"e2e_perm_user_{unique_id}", "password": "Test123!@#", "email": f"e2e_perm_user_{unique_id}@test.com", "phone": "13800138001", "nickname": "E2E权限测试用户", "status": 1, "roleId": role_id } user_response = await user_api.create_user(user_data) assert user_response.status_code == 201, "创建用户失败" user_id = user_response.json()["id"] test_data_manager.add_user(user_id) # 步骤5: 验证用户权限 user_info_response = await user_api.get_user_by_id(user_id) user_info = user_info_response.json() assert "roles" in user_info, "用户信息中缺少角色信息" # 步骤6: 修改角色权限(移除部分菜单) updated_menu_ids = menu_ids[:2] # 只保留前2个菜单 update_perm_response = await role_api.assign_menus(role_id, updated_menu_ids) assert update_perm_response.status_code == 200, "更新角色权限失败" # 步骤7: 验证权限已更新 permissions_response = await role_api.get_role_permissions(role_id) assert permissions_response.status_code == 200, "获取角色权限失败" permissions = permissions_response.json() assert len(permissions) == 2, "权限数量不正确" # 步骤8: 删除角色 delete_response = await role_api.delete_role(role_id) assert delete_response.status_code in [200, 204], "删除角色失败" async def test_e2e_file_management_workflow( self, authenticated_client, test_data_manager ): """ E2E-03: 文件上传下载流程 测试场景: 1. 上传文件 2. 验证文件信息 3. 下载文件 4. 删除文件 """ file_api = FileAPI(authenticated_client) # 步骤1: 上传文件 test_file_content = b"E2E test file content for upload" test_filename = f"e2e_test_{int(time.time() * 1000)}.txt" upload_response = await file_api.upload_file( file_content=test_file_content, filename=test_filename ) assert upload_response.status_code == 201, "文件上传失败" file_id = upload_response.json()["id"] test_data_manager.add_file(file_id) # 步骤2: 验证文件信息 file_info_response = await file_api.get_file_info(file_id) assert file_info_response.status_code == 200, "获取文件信息失败" file_info = file_info_response.json() assert file_info["fileName"] == test_filename, "文件名不匹配" # 步骤3: 下载文件 download_response = await file_api.download_file(file_id) assert download_response.status_code == 200, "文件下载失败" downloaded_content = download_response.content assert downloaded_content == test_file_content, "文件内容不匹配" # 步骤4: 删除文件 delete_response = await file_api.delete_file(file_id) assert delete_response.status_code in [200, 204], "文件删除失败" # 步骤5: 验证文件已删除 verify_delete_response = await file_api.get_file_info(file_id) assert verify_delete_response.status_code == 404, "文件未正确删除" async def test_e2e_audit_log_workflow( self, authenticated_client, test_data_manager ): """ E2E-04: 审计日志记录流程 测试场景: 1. 执行用户操作 2. 验证操作日志记录 3. 查询操作日志 4. 验证日志详情 """ user_api = UserAPI(authenticated_client) audit_api = AuditAPI(authenticated_client) unique_id = f"e2e_audit_{int(time.time() * 1000)}_{uuid.uuid4().hex[:8]}" # 步骤1: 执行用户创建操作 user_data = { "username": f"e2e_audit_user_{unique_id}", "password": "Test123!@#", "email": f"e2e_audit_user_{unique_id}@test.com", "phone": "13800138000", "nickname": "E2E审计测试用户", "status": 1 } user_response = await user_api.create_user(user_data) assert user_response.status_code == 201, "创建用户失败" user_id = user_response.json()["id"] test_data_manager.add_user(user_id) # 步骤2: 等待日志记录 await asyncio.sleep(1) # 步骤3: 查询操作日志 log_response = await audit_api.get_operation_logs( page=0, size=10 ) assert log_response.status_code == 200, "查询操作日志失败" logs = log_response.json()["content"] assert len(logs) > 0, "未找到操作日志" # 步骤4: 验证日志详情 latest_log = logs[0] assert "username" in latest_log, "日志中缺少用户名" assert "operation" in latest_log, "日志中缺少操作类型" assert "createdAt" in latest_log, "日志中缺少创建时间" # 步骤5: 清理测试数据 await user_api.delete_user(user_id) async def test_e2e_menu_management_workflow( self, authenticated_client, test_data_manager ): """ E2E-05: 菜单管理流程 测试场景: 1. 创建菜单 2. 更新菜单 3. 验证菜单树结构 4. 删除菜单 """ menu_api = MenuAPI(authenticated_client) unique_id = f"e2e_menu_{int(time.time() * 1000)}_{uuid.uuid4().hex[:8]}" # 步骤1: 创建父菜单 parent_menu_data = { "menuName": f"E2E父菜单_{unique_id}", "parentId": 0, "orderNum": 1, "menuType": "M", "status": 1, "perms": f"e2e:parent:{unique_id}", "component": "Layout" } parent_response = await menu_api.create_menu(parent_menu_data) assert parent_response.status_code == 201, "创建父菜单失败" parent_id = parent_response.json()["id"] test_data_manager.add_menu(parent_id) # 步骤2: 创建子菜单 child_menu_data = { "menuName": f"E2E子菜单_{unique_id}", "parentId": parent_id, "orderNum": 1, "menuType": "C", "status": 1, "perms": f"e2e:child:{unique_id}", "component": "views/e2e-test/index" } child_response = await menu_api.create_menu(child_menu_data) assert child_response.status_code == 201, "创建子菜单失败" child_id = child_response.json()["id"] test_data_manager.add_menu(child_id) # 步骤3: 验证菜单树结构 tree_response = await menu_api.get_menu_tree() assert tree_response.status_code == 200, "获取菜单树失败" menu_tree = tree_response.json() # 查找父菜单 parent_menu = None for menu in menu_tree: if menu["id"] == parent_id: parent_menu = menu break assert parent_menu is not None, "未找到父菜单" assert "children" in parent_menu, "父菜单缺少子菜单列表" # 验证子菜单 child_found = False for child in parent_menu["children"]: if child["id"] == child_id: child_found = True break assert child_found, "未找到子菜单" # 步骤4: 更新菜单 update_data = { "menuName": f"E2E子菜单-已更新_{unique_id}" } update_response = await menu_api.update_menu(child_id, update_data) assert update_response.status_code == 200, "更新菜单失败" # 步骤5: 验证更新结果 updated_menu_response = await menu_api.get_menu_by_id(child_id) updated_menu = updated_menu_response.json() assert updated_menu["menuName"] == update_data["menuName"], "菜单名称更新失败" # 步骤6: 删除菜单(先删除子菜单,再删除父菜单) delete_child_response = await menu_api.delete_menu(child_id) assert delete_child_response.status_code in [200, 204], "删除子菜单失败" delete_parent_response = await menu_api.delete_menu(parent_id) assert delete_parent_response.status_code in [200, 204], "删除父菜单失败" @pytest.mark.e2e @pytest.mark.integration @pytest.mark.asyncio class TestE2EIntegrationScenarios: """E2E集成场景测试类""" async def test_e2e_cross_module_workflow( self, authenticated_client, test_data_manager ): """ E2E-06: 跨模块集成测试 测试场景: 1. 创建角色并分配权限 2. 创建用户并分配角色 3. 用户执行操作 4. 验证审计日志 5. 验证权限控制 """ role_api = RoleAPI(authenticated_client) user_api = UserAPI(authenticated_client) menu_api = MenuAPI(authenticated_client) audit_api = AuditAPI(authenticated_client) unique_id = f"{int(time.time() * 1000)}_{uuid.uuid4().hex[:8]}" # 步骤1: 创建角色 role_data = { "roleName": f"E2E集成测试角色_{unique_id}", "roleKey": f"e2e_integration_role_{unique_id}", "roleSort": 1, "status": 1 } role_response = await role_api.create_role(role_data) assert role_response.status_code == 201 role_id = role_response.json()["id"] test_data_manager.add_role(role_id) # 步骤2: 创建用户 user_data = { "username": f"e2e_integration_user_{unique_id}", "password": "Test123!@#", "email": f"e2e_integration_{unique_id}@test.com", "phone": "13800138000", "nickname": "E2E集成测试用户", "status": 1, "roleId": role_id } user_response = await user_api.create_user(user_data) assert user_response.status_code == 201 user_id = user_response.json()["id"] test_data_manager.add_user(user_id) # 步骤3: 等待审计日志记录 await asyncio.sleep(1) # 步骤4: 验证审计日志 log_response = await audit_api.get_operation_logs( page=0, size=10, username=user_data["username"] ) assert log_response.status_code == 200 logs = log_response.json()["content"] # 注意: 如果后端审计日志功能未完整实现,此断言可能失败 # 建议后端团队完善审计日志记录功能 if len(logs) == 0: import warnings warnings.warn( "审计日志功能未完整实现,建议后端团队完善审计日志记录功能", UserWarning ) else: assert len(logs) > 0, "未找到相关审计日志" # 步骤5: 清理数据 await user_api.delete_user(user_id) await role_api.delete_role(role_id)