Files
item_bank/tests/conftest.py
T
2026-08-01 16:50:55 +08:00

83 lines
2.7 KiB
Python

"""测试夹具:每个测试用独立的临时 SQLite 库。"""
import os
import tempfile
from pathlib import Path
# 必须在导入 app 之前设置环境变量(config 是模块级单例)
_tmpdir = tempfile.mkdtemp(prefix="item-bank-test-")
os.environ["DATABASE_URL"] = f"sqlite+aiosqlite:///{_tmpdir}/test.db"
os.environ["DEBUG"] = "false"
os.environ["RATE_LIMIT_ENABLED"] = "false" # 默认关掉,限流测试里单独开
# 需满足 config.check_production_secrets 的要求(≥32 字节、非默认值)
os.environ["JWT_SECRET"] = "test-secret-long-enough-for-hs256-abcdefghij"
import pytest # noqa: E402
import pytest_asyncio # noqa: E402
from cryptography.fernet import Fernet # noqa: E402
from httpx import ASGITransport, AsyncClient # noqa: E402
# 生成合法的 Fernet key 并在导入 app 前写入
os.environ["FERNET_KEY"] = Fernet.generate_key().decode()
import app.models # noqa: E402,F401 注册所有模型
from app.db import Base, engine # noqa: E402
from app.main import app as fastapi_app # noqa: E402
@pytest_asyncio.fixture
async def db_schema():
"""每个测试前重建表,测试间互不干扰。"""
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.drop_all)
await conn.run_sync(Base.metadata.create_all)
yield
@pytest_asyncio.fixture
async def client(db_schema):
transport = ASGITransport(app=fastapi_app)
async with AsyncClient(transport=transport, base_url="http://test") as c:
yield c
@pytest_asyncio.fixture
async def auth_headers(client):
"""注册并登录一个用户,返回可直接用的鉴权头。"""
async def _make(username: str = "alice", password: str = "secret123") -> dict:
await client.post(
"/api/auth/register", json={"username": username, "password": password}
)
resp = await client.post(
"/api/auth/login", data={"username": username, "password": password}
)
token = resp.json()["access_token"]
return {"Authorization": f"Bearer {token}"}
return _make
@pytest_asyncio.fixture
async def configure_ai(client):
"""给某个用户配好 AI 接口(api_key 会被加密存储)。"""
async def _make(headers: dict, api_key: str = "sk-test-value") -> dict:
resp = await client.put(
"/api/settings",
json={
"llm_base_url": "http://fake-llm",
"llm_text_model": "text-model",
"llm_vision_model": "vision-model",
"api_key": api_key,
},
headers=headers,
)
assert resp.status_code == 200
return resp.json()
return _make
def pytest_configure(config):
config.addinivalue_line("markers", "asyncio: async test")