From 41fa4e016f32c34ebf8915a96491729ac449e0c5 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Tue, 15 Sep 2026 17:05:00 +0800 Subject: [PATCH] =?UTF-8?q?fix(#1894):=20=E4=BF=AE=E5=A4=8D=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E5=85=BC=E5=AE=B9=E6=80=A7=20=E2=80=94=20mock?= =?UTF-8?q?=E5=AD=97=E6=AE=B5/API=E8=B7=AF=E5=BE=84/auth=E8=A6=86=E7=9B=96?= =?UTF-8?q?/ASCII=20header?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/api/app/api/routes/titles.py | 2 +- tests/unit/test_script_title_integration.py | 141 ++++++++++++-------- tests/unit/test_scripts_routes.py | 14 +- 3 files changed, 98 insertions(+), 59 deletions(-) diff --git a/apps/api/app/api/routes/titles.py b/apps/api/app/api/routes/titles.py index cf8d7b203..fd0fea807 100755 --- a/apps/api/app/api/routes/titles.py +++ b/apps/api/app/api/routes/titles.py @@ -43,7 +43,7 @@ from packages.ports.user_repository import UserRepository router = APIRouter() logger = logging.getLogger(__name__) -_DEPRECATION_WARNING = "标题库 API 已废弃,请迁移到 scripts 的 title_text/title_category/title_config 字段(#1894)" +_DEPRECATION_WARNING = "title_library API deprecated, migrate to scripts title_text/title_category/title_config fields (#1894)" def _deprecation_headers() -> dict: diff --git a/tests/unit/test_script_title_integration.py b/tests/unit/test_script_title_integration.py index 63ed2707e..672097549 100644 --- a/tests/unit/test_script_title_integration.py +++ b/tests/unit/test_script_title_integration.py @@ -17,7 +17,7 @@ from unittest.mock import MagicMock, patch import pytest from fastapi.testclient import TestClient -from app.main import app +from main import app # ── helpers ────────────────────────────────────────────────────────────── @@ -187,10 +187,7 @@ class TestScriptServiceCreateWithNewFields: class TestScriptsRoutesNewFields: """验证 scripts API 路由正确处理新字段.""" - @patch("app.api.routes.scripts._get_service") - @patch("app.auth.get_current_user") - def test_create_script_passes_title_fields(self, mock_auth, mock_svc_dep): - mock_auth.return_value = MagicMock(user=MagicMock(id="user-001")) + def test_create_script_passes_title_fields(self): mock_script = _make_script( title_text="测试标题", title_category="片头", @@ -198,32 +195,38 @@ class TestScriptsRoutesNewFields: ) mock_svc = MagicMock() mock_svc.create_script.return_value = mock_script - mock_svc_dep.return_value = mock_svc - client = TestClient(app) - resp = client.post( - "/scripts", - json={ - "title": "新文案", - "content": "内容", - "title_text": "测试标题", - "title_category": "片头", - "title_config": {"text": "测试标题", "font_size": 48}, - }, - headers={"X-User-Id": "user-001"}, - ) + from app.auth import get_current_user + from app.api.routes.scripts import _get_service + async def _fake_user(): + return MagicMock(user=MagicMock(id="user-001")) + def _fake_svc(): + return mock_svc + app.dependency_overrides[get_current_user] = _fake_user + app.dependency_overrides[_get_service] = _fake_svc + try: + client = TestClient(app) + resp = client.post( + "/api/v1/scripts", + json={ + "title": "新文案", + "content": "内容", + "title_text": "测试标题", + "title_category": "片头", + "title_config": {"text": "测试标题", "font_size": 48}, + }, + headers={"X-User-Id": "user-001"}, + ) - assert resp.status_code == 201 - # 验证 service 被调用时传入了新字段 - call_kwargs = mock_svc.create_script.call_args[1] - assert call_kwargs["title_text"] == "测试标题" - assert call_kwargs["title_category"] == "片头" - assert call_kwargs["title_config"] == {"text": "测试标题", "font_size": 48} + assert resp.status_code == 201 + call_kwargs = mock_svc.create_script.call_args[1] + assert call_kwargs["title_text"] == "测试标题" + assert call_kwargs["title_category"] == "片头" + assert call_kwargs["title_config"] == {"text": "测试标题", "font_size": 48} + finally: + app.dependency_overrides.clear() - @patch("app.api.routes.scripts._get_service") - @patch("app.auth.get_current_user") - def test_get_script_response_includes_title_fields(self, mock_auth, mock_svc_dep): - mock_auth.return_value = MagicMock(user=MagicMock(id="user-001")) + def test_get_script_response_includes_title_fields(self): mock_script = _make_script( title_text="响应标题", title_category="片尾", @@ -231,16 +234,26 @@ class TestScriptsRoutesNewFields: ) mock_svc = MagicMock() mock_svc.get_script.return_value = mock_script - mock_svc_dep.return_value = mock_svc - client = TestClient(app) - resp = client.get("/scripts/script-123", headers={"X-User-Id": "user-001"}) + from app.auth import get_current_user + from app.api.routes.scripts import _get_service + async def _fake_user(): + return MagicMock(user=MagicMock(id="user-001")) + def _fake_svc(): + return mock_svc + app.dependency_overrides[get_current_user] = _fake_user + app.dependency_overrides[_get_service] = _fake_svc + try: + client = TestClient(app) + resp = client.get("/api/v1/scripts/script-123", headers={"X-User-Id": "user-001"}) - assert resp.status_code == 200 - data = resp.json() - assert data["title_text"] == "响应标题" - assert data["title_category"] == "片尾" - assert data["title_config"]["position"] == "bottom" + assert resp.status_code == 200 + data = resp.json() + assert data["title_text"] == "响应标题" + assert data["title_category"] == "片尾" + assert data["title_config"]["position"] == "bottom" + finally: + app.dependency_overrides.clear() # ── TestTitleLibraryDeprecated ─────────────────────────────────────────── @@ -248,24 +261,28 @@ class TestScriptsRoutesNewFields: class TestTitleLibraryDeprecated: """验证 title_libraries API 返回 deprecated Warning header.""" - @patch("app.api.routes.titles._get_title_repository") - @patch("app.auth.get_current_user") - def test_list_titles_has_warning_header(self, mock_auth, mock_repo_dep): - mock_auth.return_value = MagicMock(user=MagicMock(id="user-001")) + def test_list_titles_has_warning_header(self): mock_repo = MagicMock() mock_repo.count_by_user.return_value = 0 - mock_repo_dep.return_value = mock_repo - client = TestClient(app) - resp = client.get("/titles", headers={"X-User-Id": "user-001"}) + from app.auth import get_current_user + from app.api.routes.titles import _get_title_repository + async def _fake_user(): + return MagicMock(user=MagicMock(id="user-001")) + def _fake_repo(): + return mock_repo + app.dependency_overrides[get_current_user] = _fake_user + app.dependency_overrides[_get_title_repository] = _fake_repo + try: + client = TestClient(app) + resp = client.get("/api/v1/titles", headers={"X-User-Id": "user-001"}) - assert resp.status_code == 200 - assert "Warning" in resp.headers or "warning" in {k.lower() for k in resp.headers} + assert resp.status_code == 200 + assert "Warning" in resp.headers or "warning" in {k.lower() for k in resp.headers} + finally: + app.dependency_overrides.clear() - @patch("app.api.routes.titles._get_title_repository") - @patch("app.auth.get_current_user") - def test_get_title_has_warning_header(self, mock_auth, mock_repo_dep): - mock_auth.return_value = MagicMock(user=MagicMock(id="user-001")) + def test_get_title_has_warning_header(self): from packages.domain.title_library import TitleLibraryItem mock_item = TitleLibraryItem( id="t1", user_id="user-001", name="测试", text="标题文字", @@ -274,12 +291,22 @@ class TestTitleLibraryDeprecated: updated_at=datetime(2026, 1, 1, tzinfo=timezone.utc), ) mock_repo = MagicMock() - mock_repo_dep.return_value = mock_repo - with patch("packages.application.title_library.use_cases.GetTitleLibraryUseCase") as mock_uc: - mock_uc.return_value.execute.return_value = mock_item - client = TestClient(app) - resp = client.get("/titles/t1", headers={"X-User-Id": "user-001"}) - assert resp.status_code == 200 - warning_header = resp.headers.get("Warning", "") - assert "1894" in warning_header or "deprecated" in warning_header.lower() or "废弃" in warning_header + from app.auth import get_current_user + from app.api.routes.titles import _get_title_repository + async def _fake_user(): + return MagicMock(user=MagicMock(id="user-001")) + def _fake_repo(): + return mock_repo + app.dependency_overrides[get_current_user] = _fake_user + app.dependency_overrides[_get_title_repository] = _fake_repo + try: + with patch("app.api.routes.titles.GetTitleLibraryUseCase") as mock_uc: + mock_uc.return_value.execute.return_value = mock_item + client = TestClient(app) + resp = client.get("/api/v1/titles/t1", headers={"X-User-Id": "user-001"}) + assert resp.status_code == 200 + warning_header = resp.headers.get("Warning", "") + assert "1894" in warning_header or "deprecated" in warning_header.lower() + finally: + app.dependency_overrides.clear() diff --git a/tests/unit/test_scripts_routes.py b/tests/unit/test_scripts_routes.py index 71c67cbe3..a92827c67 100644 --- a/tests/unit/test_scripts_routes.py +++ b/tests/unit/test_scripts_routes.py @@ -116,7 +116,7 @@ class TestScriptResponse: segments=[], tags=[], created_at=now, updated_at=now, ) assert r.title_text == "" - assert r.title_category == "default" + assert r.title_category == "" assert r.title_config == {} @@ -167,6 +167,9 @@ class TestRouteHandlers: mock_script.content = "内容" mock_script.segments = [{"text": "段1", "duration": None}] mock_script.tags = [] + mock_script.title_text = "" + mock_script.title_category = "" + mock_script.title_config = {} mock_script.created_at = datetime(2026, 9, 8, tzinfo=UTC) mock_script.updated_at = datetime(2026, 9, 8, tzinfo=UTC) svc.create_script.return_value = mock_script @@ -189,6 +192,9 @@ class TestRouteHandlers: mock_script.content = "" mock_script.segments = [] mock_script.tags = [] + mock_script.title_text = "" + mock_script.title_category = "" + mock_script.title_config = {} mock_script.created_at = datetime(2026, 9, 8, tzinfo=UTC) mock_script.updated_at = datetime(2026, 9, 8, tzinfo=UTC) svc.list_scripts.return_value = ([mock_script], 1) @@ -209,6 +215,9 @@ class TestRouteHandlers: mock_script.content = "" mock_script.segments = [] mock_script.tags = [] + mock_script.title_text = "" + mock_script.title_category = "" + mock_script.title_config = {} mock_script.created_at = datetime(2026, 9, 8, tzinfo=UTC) mock_script.updated_at = datetime(2026, 9, 8, tzinfo=UTC) svc.get_script.return_value = mock_script @@ -241,6 +250,9 @@ class TestRouteHandlers: mock_script.content = "原内容" mock_script.segments = [] mock_script.tags = [] + mock_script.title_text = "" + mock_script.title_category = "" + mock_script.title_config = {} mock_script.created_at = datetime(2026, 9, 8, tzinfo=UTC) mock_script.updated_at = datetime(2026, 9, 8, tzinfo=UTC) svc.update_script.return_value = mock_script