""" pytest 全局配置 ============================================================= P1 阶段: - flask_app fixture:最小 Flask 应用(供 jsonify 等需应用上下文的功能测试) - 项目根目录加入 sys.path P8 阶段补充(测试完善): - app fixture:create_app() + 测试库 DATABASE_URL 覆盖 - db fixture:事务内建表/清库 - client fixture:Flask test_client """ import os import sys import pytest from flask import Flask # 项目根目录加入 sys.path(tests/ 已有 __init__.py 时 pytest 通常自动处理, # 此处显式补充,兼容从任意目录启动 pytest 的场景) ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) if ROOT not in sys.path: sys.path.insert(0, ROOT) @pytest.fixture def flask_app(): """ 最小 Flask 应用实例(无数据库/中间件,仅提供应用上下文)。 配置项说明: - SECRET_KEY: FlaskForm CSRF 校验需要 - WTF_CSRF_ENABLED=False: 单元测试关闭 CSRF """ app = Flask(__name__) app.config['SECRET_KEY'] = 'test-secret-key' app.config['WTF_CSRF_ENABLED'] = False return app @pytest.fixture def app(): """ sqlite 内存库应用实例:供 Repository 单测使用。 - StaticPool 保证所有连接共享同一内存库(多线程/多次 init 下数据一致) - 每测试独立建表/drop(query.update / bulk_insert 与 identity map 冲突, 不宜采用事务回滚隔离) - 测试内数据构造需显式 db.session.commit() """ from sqlalchemy.pool import StaticPool from src.core.database import db import src.models_registry # noqa: F401 (注册全部表) flask_app = Flask(__name__) flask_app.config.update( TESTING=True, SECRET_KEY='test-secret-key', WTF_CSRF_ENABLED=False, SQLALCHEMY_DATABASE_URI='sqlite://', SQLALCHEMY_TRACK_MODIFICATIONS=False, SQLALCHEMY_ENGINE_OPTIONS={'poolclass': StaticPool}, ) db.init_app(flask_app) with flask_app.app_context(): db.create_all() yield flask_app db.session.remove() db.drop_all()