""" 全局测试夹具 提供pytest全局夹具和钩子函数。 """ import os import sys import pytest from pathlib import Path from typing import Generator # 添加项目根目录到Python路径 project_root = Path(__file__).parent sys.path.insert(0, str(project_root)) from playwright.sync_api import Page, Browser, BrowserContext from core.config_manager import config_manager from core.logger import get_logger from core.reporter import TestReporter, TestResult from pages.web import LoginPage, DashboardPage, UserManagementPage, RoleManagementPage, MenuManagementPage from pages.uniapp import AlmanacPage, CalendarPage, UserPage # 配置管理器 @pytest.fixture(scope="session") def test_config(): """测试配置夹具""" return config_manager.get_config() # 日志记录器 @pytest.fixture(scope="session") def logger(): """日志记录器夹具""" return get_logger() # 测试报告 @pytest.fixture(scope="session") def test_reporter(): """测试报告夹具""" reporter = TestReporter() reporter.start_report() yield reporter reporter.end_report() reporter.generate_all_reports() # Admin端页面对象 @pytest.fixture def login_page(page: Page, test_config): """登录页面对象""" return LoginPage(page, test_config.base_url) @pytest.fixture def dashboard_page(page: Page, test_config): """仪表盘页面对象""" return DashboardPage(page, test_config.base_url) @pytest.fixture def user_management_page(page: Page, test_config): """用户管理页面对象""" return UserManagementPage(page, test_config.base_url) @pytest.fixture def role_management_page(page: Page, test_config): """角色管理页面对象""" return RoleManagementPage(page, test_config.base_url) @pytest.fixture def menu_management_page(page: Page, test_config): """菜单管理页面对象""" return MenuManagementPage(page, test_config.base_url) # Uniapp端页面对象 @pytest.fixture def almanac_page(page: Page, test_config): """黄历页面对象""" # 使用uniapp的base_url import yaml from pathlib import Path config_path = Path(__file__).parent / "config" / "config.yaml" with open(config_path, "r", encoding="utf-8") as f: data = yaml.safe_load(f) env = os.getenv("TEST_ENV", "dev") uniapp_base_url = data["environments"][env]["uniapp"]["base_url"] return AlmanacPage(page, uniapp_base_url) @pytest.fixture def calendar_page(page: Page, test_config): """日历页面对象""" # 使用uniapp的base_url import yaml from pathlib import Path config_path = Path(__file__).parent / "config" / "config.yaml" with open(config_path, "r", encoding="utf-8") as f: data = yaml.safe_load(f) env = os.getenv("TEST_ENV", "dev") uniapp_base_url = data["environments"][env]["uniapp"]["base_url"] return CalendarPage(page, uniapp_base_url) @pytest.fixture def user_page(page: Page, test_config): """用户页面对象""" # 使用uniapp的base_url import yaml from pathlib import Path config_path = Path(__file__).parent / "config" / "config.yaml" with open(config_path, "r", encoding="utf-8") as f: data = yaml.safe_load(f) env = os.getenv("TEST_ENV", "dev") uniapp_base_url = data["environments"][env]["uniapp"]["base_url"] return UserPage(page, uniapp_base_url) # 认证夹具 @pytest.fixture def authenticated_page(page: Page, test_config): """已认证页面夹具""" login_page = LoginPage(page, test_config.base_url) login_page.navigate() # 使用配置中的用户登录 users = test_config.users if "admin" in users: login_page.login( users["admin"]["username"], users["admin"]["password"] ) else: login_page.login("admin", "admin123") # 等待跳转到仪表盘 login_page.wait_for_redirect() return page @pytest.fixture def web_page(page: Page, test_config): """Web页面夹具(已认证)""" login_page = LoginPage(page, test_config.base_url) login_page.navigate() # 使用配置中的用户登录 users = test_config.users if "admin" in users: login_page.login( users["admin"]["username"], users["admin"]["password"] ) else: login_page.login("admin", "admin123") # 等待跳转到仪表盘 login_page.wait_for_redirect() return page @pytest.fixture def integration_test_data(page: Page, test_config, user_management_page, role_management_page): """ 集成测试数据准备fixture 为集成测试准备必要的测试数据,包括: - 测试角色 - 测试用户 - 测试菜单 """ import uuid # 生成唯一标识 unique_id = str(uuid.uuid4())[:8] # 准备测试角色 role_name = f"集成测试角色_{unique_id}" role_code = f"integration_role_{unique_id}" try: role_management_page.navigate() role_management_page.wait_for_load() # 创建测试角色 role_management_page.click_create_button() role_management_page.fill_form_name(role_name) role_management_page.fill_form_code(role_code) role_management_page.fill_form_description("集成测试专用角色") role_management_page.click_form_submit() # 等待创建完成 try: role_management_page.wait_for_success_message() except: pass except Exception as e: print(f"创建测试角色失败: {e}") # 准备测试用户 username = f"集成测试用户_{unique_id}" email = f"integration_{unique_id}@example.com" try: user_management_page.navigate() user_management_page.wait_for_load() # 创建测试用户 user_management_page.click_create_button() user_management_page.fill_form_username(username) user_management_page.fill_form_nickname("集成测试用户") user_management_page.fill_form_email(email) user_management_page.fill_form_phone("13800138000") user_management_page.click_form_submit() # 等待创建完成 try: user_management_page.wait_for_success_message() except: pass except Exception as e: print(f"创建测试用户失败: {e}") # 返回测试数据 return { "role": { "name": role_name, "code": role_code }, "user": { "username": username, "email": email }, "unique_id": unique_id } @pytest.fixture def cleanup_test_data(page: Page, test_config, user_management_page, role_management_page): """ 集成测试数据清理fixture 清理集成测试创建的测试数据 """ yield # 测试结束后清理数据 try: # 删除测试角色 role_management_page.navigate() role_management_page.wait_for_load() # 搜索测试角色 role_management_page.fill_search("集成测试角色_") role_management_page.click_search() role_management_page.wait_for_table_load() # 删除找到的测试角色 rows = role_management_page.get_table_rows_count() for i in range(rows): try: role_management_page.click_row_delete(0) role_management_page.confirm_delete() role_management_page.wait_for_success_message() except: pass except Exception as e: print(f"清理测试角色失败: {e}") try: # 删除测试用户 user_management_page.navigate() user_management_page.wait_for_load() # 搜索测试用户 user_management_page.fill_search("集成测试用户_") user_management_page.click_search() user_management_page.wait_for_table_load() # 删除找到的测试用户 rows = user_management_page.get_table_rows_count() for i in range(rows): try: user_management_page.click_row_delete(0) user_management_page.confirm_delete() user_management_page.wait_for_success_message() except: pass except Exception as e: print(f"清理测试用户失败: {e}") # pytest钩子函数 def pytest_configure(config): """pytest配置钩子""" # 添加自定义标记 config.addinivalue_line("markers", "smoke: 冒烟测试") config.addinivalue_line("markers", "regression: 回归测试") config.addinivalue_line("markers", "admin: Admin端测试") config.addinivalue_line("markers", "uniapp: Uniapp端测试") config.addinivalue_line("markers", "slow: 慢速测试") def pytest_collection_modifyitems(config, items): """测试收集修改钩子""" # 自动添加标记 for item in items: # 根据测试名称自动添加标记 if "admin" in item.nodeid.lower(): item.add_marker(pytest.mark.admin) if "uniapp" in item.nodeid.lower(): item.add_marker(pytest.mark.uniapp) @pytest.hookimpl(tryfirst=True, hookwrapper=True) def pytest_runtest_makereport(item, call): """测试结果报告钩子""" outcome = yield report = outcome.get_result() # 获取测试名称 test_name = item.nodeid # 记录测试结果 if report.when == "call": status = report.outcome # 获取page对象(如果存在) page = None for fixture_name in item.fixturenames: if fixture_name == "page": try: page = item.funcargs.get("page") except: pass break # 截图(如果失败) if status == "failed" and page: try: from core.screenshot_helper import ScreenshotHelper screenshot_helper = ScreenshotHelper() screenshot_helper.take_screenshot_on_failure(page, test_name) except: pass def pytest_sessionfinish(session, exitstatus): """测试会话结束钩子""" print("\n" + "="*60) print("测试执行完成") print(f"退出状态: {exitstatus}") print("="*60)