Files
xiaoxia-saas/tests/unit/test_phase8_edit_models.py
CI Bot 1a57878f76
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Failing after 1m12s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 2m17s
CI/CD Pipeline / Integration Tests (pull_request) Failing after 1m33s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 3m14s
CI/CD Pipeline / Build & Push Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Build Production Runtime Images (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
chore(backend): Phase 3 清理 — 未使用依赖删除 + pyflakes 警告清零 + 测试文件冗余清理
1. 未使用依赖清理:
   - 从 requirements-base.txt 移除 cryptography 和 pyOpenSSL

2. pyflakes 警告清零 (apps/ + packages/ + tests/):
   - 移除 17 处未使用的 import (F401)
   - 修复 26 处未使用的局部变量 (F841):
     * 有副作用的赋值转为裸调用
     * 无副作用的赋值直接删除
   - 修复 1 处未使用的异常变量 (F841)
   - 修复 1 处空 except 块

3. 测试文件冗余清理:
   - 删除 tests/integration/test_project_management.py (模块级 skip,测试不存在的模块)
   - 删除 tests/integration/fixtures/duplication_routes_fixed.py (未被引用)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 16:14:46 +08:00

214 lines
7.3 KiB
Python

"""Unit tests for Phase 8 EditTemplate and EditPlan domain entities + repositories."""
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "apps" / "api"))
import logging
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from packages.adapters.sqlalchemy_impl.edit_plan_repository import (
SQLAlchemyEditPlanRepository,
)
from packages.adapters.sqlalchemy_impl.edit_template_repository import (
SQLAlchemyEditTemplateRepository,
)
from packages.adapters.sqlalchemy_impl.models import Base
from packages.domain.edit_plan import EditPlan, EditPlanStatus
from packages.domain.edit_template import EditTemplate, EditTemplateStatus
logger = logging.getLogger(__name__)
# ── EditTemplate 领域实体测试 ──────────────────────────────────────────
class TestEditTemplate:
def test_create_success(self):
t = EditTemplate.create("vlog模板", description="日常vlog", template_type="vlog")
assert t.name == "vlog模板"
assert t.description == "日常vlog"
assert t.template_type == "vlog"
assert t.status == EditTemplateStatus.ACTIVE
assert t.config == {}
assert t.sort_weight == 0
assert t.id # 自动生成
def test_create_strips_whitespace(self):
t = EditTemplate.create(" 模板 ")
assert t.name == "模板"
def test_create_empty_name_raises(self):
try:
EditTemplate.create(" ")
assert False, "应该抛出 ValueError"
except ValueError as e:
assert "模板名称不能为空" in str(e)
def test_activate_deactivate(self):
t = EditTemplate.create("test")
assert t.is_active is True
t.deactivate()
assert t.is_active is False
assert t.status == EditTemplateStatus.INACTIVE
t.activate()
assert t.is_active is True
assert t.status == EditTemplateStatus.ACTIVE
# ── EditPlan 领域实体测试 ──────────────────────────────────────────────
class TestEditPlan:
def test_create_success(self):
p = EditPlan.create("tpl-1", "我的计划", config={"bgm": "happy"})
assert p.template_id == "tpl-1"
assert p.name == "我的计划"
assert p.status == EditPlanStatus.DRAFT
assert p.config == {"bgm": "happy"}
assert p.total_duration == 0.0
def test_create_empty_name_raises(self):
try:
EditPlan.create("tpl-1", " ")
assert False, "应该抛出 ValueError"
except ValueError as e:
assert "计划名称不能为空" in str(e)
def test_create_empty_template_id_raises(self):
try:
EditPlan.create(" ", "test")
assert False, "应该抛出 ValueError"
except ValueError as e:
assert "template_id 不能为空" in str(e)
def test_status_transitions_happy_path(self):
p = EditPlan.create("tpl-1", "test")
assert p.status == EditPlanStatus.DRAFT
p.start_editing()
assert p.status == EditPlanStatus.EDITING
p.start_rendering()
assert p.status == EditPlanStatus.RENDERING
p.mark_completed()
assert p.status == EditPlanStatus.COMPLETED
def test_status_transitions_failure_path(self):
p = EditPlan.create("tpl-1", "test")
p.start_editing()
p.start_rendering()
p.mark_failed()
assert p.status == EditPlanStatus.FAILED
p.reset_to_draft()
assert p.status == EditPlanStatus.DRAFT
def test_invalid_transition_raises(self):
p = EditPlan.create("tpl-1", "test")
try:
p.start_rendering() # draft → rendering 不合法
assert False, "应该抛出 ValueError"
except ValueError as e:
logger.warning(f"Operation failed in tests/unit/test_phase8_edit_models.py: {e}", exc_info=True)
def test_mark_completed_from_non_rendering_raises(self):
p = EditPlan.create("tpl-1", "test")
try:
p.mark_completed() # draft → completed 不合法
assert False, "应该抛出 ValueError"
except ValueError as e:
logger.warning(f"Operation failed in tests/unit/test_phase8_edit_models.py: {e}", exc_info=True)
def test_reset_from_non_failed_raises(self):
p = EditPlan.create("tpl-1", "test")
try:
p.reset_to_draft() # draft → draft 不合法
assert False, "应该抛出 ValueError"
except ValueError as e:
logger.warning(f"Operation failed in tests/unit/test_phase8_edit_models.py: {e}", exc_info=True)
# ── Repository 集成测试(内存 SQLite) ─────────────────────────────────
class TestRepositories:
def _make_session(self):
engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(engine)
SessionLocal = sessionmaker(bind=engine)
return SessionLocal()
def test_edit_template_repository_crud(self):
session = self._make_session()
try:
repo = SQLAlchemyEditTemplateRepository(session)
t = EditTemplate.create("模板A", description="测试模板")
repo.create(t)
fetched = repo.get(t.id)
assert fetched is not None
assert fetched.name == "模板A"
assert fetched.description == "测试模板"
# list
active = repo.list_active()
assert len(active) == 1
assert active[0].id == t.id
# update
fetched.deactivate()
repo.update(fetched)
assert repo.get(t.id).status == EditTemplateStatus.INACTIVE
assert len(repo.list_active()) == 0
# count
assert repo.count() == 1
# delete
assert repo.delete(t.id) is True
assert repo.get(t.id) is None
assert repo.count() == 0
finally:
session.close()
def test_edit_plan_repository_crud(self):
session = self._make_session()
try:
repo = SQLAlchemyEditPlanRepository(session)
p = EditPlan.create("tpl-1", "计划A", config={"key": "val"})
repo.create(p)
fetched = repo.get(p.id)
assert fetched is not None
assert fetched.name == "计划A"
assert fetched.config == {"key": "val"}
assert fetched.status == EditPlanStatus.DRAFT
# list_by_template
plans = repo.list_by_template("tpl-1")
assert len(plans) == 1
# update status
fetched.start_editing()
repo.update(fetched)
editing = repo.list_by_template("tpl-1", status=EditPlanStatus.EDITING)
assert len(editing) == 1
# count
assert repo.count() == 1
assert repo.count(status=EditPlanStatus.EDITING) == 1
assert repo.count(status=EditPlanStatus.DRAFT) == 0
# delete
assert repo.delete(p.id) is True
assert repo.get(p.id) is None
finally:
session.close()