chore: P1 验证通过 + 应用工厂抽取(修复循环导入)

- application/factory.py:应用工厂独立成模块,application 包保持轻量
  (修复 utils→application.constants 触发全量导入的循环依赖,P2 前置改造)
- app.py 改为 from application.factory import create_app
- tests/conftest.py:新增 flask_app 上下文 fixture
- test_response.py:R.ok/failed 在应用上下文中测试
- .flake8:修复 extend-ignore 行内注释导致 flake8 解析失败

验证:
- pytest 5 passed
- 应用完整构建 OK(MySQL/Redis 就绪)
- flake8 存量基线 154 条(F401×111 / E402×36 / 其余 7)已登记

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
DjangoAdmin Dev
2026-08-07 12:22:56 +08:00
co-authored by Claude
parent 8691412ec6
commit 92130ef070
7 changed files with 238 additions and 146 deletions
+17 -5
View File
@@ -2,18 +2,30 @@
pytest 全局配置
=============================================================
P1 阶段仅搭建骨架,保证 `pytest` 可空跑。
测试 App 构建、数据库/Redis fixture 在 P8(测试完善阶段)补充:
- app fixture:create_app() + 测试库 DATABASE_URL 覆盖
- db fixture:事务内建表/清库
- client fixture:Flask test_client
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 应用实例(无数据库/中间件,仅提供应用上下文)。"""
return Flask(__name__)
+19 -10
View File
@@ -3,6 +3,9 @@ R 统一响应格式单元测试
验证 `R.ok()` / `R.failed()` 返回的 JSON 响应结构符合前后端约定:
{code, data, msg, ok}(code=0 成功,非 0 失败)。
说明:`R.ok()` 内部使用 `jsonify`,须在 Flask 应用上下文内调用
(fixture:flask_app,见 tests/conftest.py)。
"""
from utils import R
@@ -11,8 +14,9 @@ from utils import R
class TestOk:
"""成功响应"""
def test_ok_default_format(self):
resp = R.ok()
def test_ok_default_format(self, flask_app):
with flask_app.app_context():
resp = R.ok()
body = resp.get_json()
assert body["code"] == 0
@@ -20,33 +24,38 @@ class TestOk:
assert body["data"] is None
assert body["msg"]
def test_ok_with_data(self):
resp = R.ok(data={"id": 1, "name": "张三"})
def test_ok_with_data(self, flask_app):
with flask_app.app_context():
resp = R.ok(data={"id": 1, "name": "张三"})
body = resp.get_json()
assert body["code"] == 0
assert body["data"] == {"id": 1, "name": "张三"}
def test_ok_with_kwargs(self):
resp = R.ok(data=[], total=100)
def test_ok_with_kwargs(self, flask_app):
with flask_app.app_context():
resp = R.ok(data=[], total=100)
body = resp.get_json()
assert body["code"] == 0
assert body["total"] == 100
class TestFailed:
"""失败响应"""
def test_failed_default_format(self):
resp = R.failed()
def test_failed_default_format(self, flask_app):
with flask_app.app_context():
resp = R.failed()
body = resp.get_json()
assert body["code"] != 0
assert body["ok"] is False
assert body["data"] is None
def test_failed_custom_code(self):
resp = R.failed(msg="未授权访问", code=401)
def test_failed_custom_code(self, flask_app):
with flask_app.app_context():
resp = R.failed(msg="未授权访问", code=401)
body = resp.get_json()
assert body["code"] == 401