"""pytest 配置与公共 fixture(依据 API 文档) 测试与开发环境严格隔离:测试通过 HTTP 请求已启动的后端服务,不加载应用代码、不 mock 认证。 运行测试前请先启动后端:http://127.0.0.1:8000 """ import os import httpx import pytest # 已启动的后端服务地址(可通过环境变量 TEST_BASE_URL 覆盖) BASE_URL = os.environ.get("TEST_BASE_URL", "http://127.0.0.1:8000") @pytest.fixture(scope="session") def http_client(): """请求已启动的后端服务的 HTTP 客户端(session 级,复用连接)""" with httpx.Client(base_url=BASE_URL, timeout=30.0) as c: yield c @pytest.fixture def client(http_client): """请求已启动的后端服务的 HTTP 客户端(测试用别名)""" return http_client def _login(client: httpx.Client, username: str, password: str) -> str: """登录并返回 token,失败则抛出异常。""" r = client.post( "/api/auth/login", json={"username": username, "password": password}, ) if r.status_code != 200: raise RuntimeError( f"登录失败 {r.status_code}: {r.text}. 请确认后端已启动({BASE_URL})且存在用户 {username} / 密码 123456。" ) body = r.json() if "token" not in body: raise RuntimeError(f"登录响应缺少 token: {body}") return body["token"] @pytest.fixture(scope="session") def auth_token(http_client): """已登录的任意角色 token(admin,用于列表/详情/更新/日志等)""" return _login(http_client, "admin", "123456") @pytest.fixture(scope="session") def market_token(http_client): """市场部账号 token(仅市场部可新建项目)""" return _login(http_client, "market", "123456") @pytest.fixture(scope="session") def engineer_token(http_client): """工程部账号 token(非市场部,用于 403 等用例)""" return _login(http_client, "engineer", "123456")