Files
xiaoxia-saas/tests/unit/test_generated_videos_use_cases.py
T
xiaoxia 2ee110f19c
CI/CD Pipeline / Check if frontend-only change (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (push) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Lint (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / PR Build API Image (push) Has been cancelled
CI/CD Pipeline / PR Build Web Image (push) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
test: P3-1 第33波单元测试(projects/generated_videos/duplication) (#810)
2026-07-24 11:25:49 +08:00

320 lines
10 KiB
Python
Executable File

"""生成视频 UseCase 单元测试."""
from __future__ import annotations
from unittest.mock import MagicMock
import pytest
from packages.application.generated_videos import (
GetGeneratedVideoDownloadUrlUseCase,
GetGeneratedVideoUseCase,
GetVideosByIdsUseCase,
ListGeneratedVideosByTaskUseCase,
ListGeneratedVideosPaginatedUseCase,
ListGeneratedVideosUseCase,
UpdateVideoReviewStatusUseCase,
)
from packages.domain.generated_video import GeneratedVideo
@pytest.fixture
def mock_repo():
return MagicMock()
@pytest.fixture
def sample_video():
v = GeneratedVideo.create(
project_id="proj_1",
generation_task_id="task_1",
name="测试视频",
file_url="https://oss.example.com/videos/test.mp4",
user_id="user_1",
file_size=1024000,
duration=30.5,
width=1920,
height=1080,
fps=30.0,
)
v.id = "video_123"
return v
class TestListGeneratedVideosUseCase:
"""ListGeneratedVideosUseCase 测试"""
def test_list_returns_results(self, mock_repo, sample_video):
"""正常返回项目生成视频列表"""
mock_repo.list_by_project.return_value = [sample_video]
use_case = ListGeneratedVideosUseCase(mock_repo)
result = use_case.execute("proj_1")
assert len(result) == 1
assert result[0].id == "video_123"
mock_repo.list_by_project.assert_called_once_with("proj_1")
def test_empty_project_id_raises(self, mock_repo):
"""空 project_id 抛出"""
use_case = ListGeneratedVideosUseCase(mock_repo)
with pytest.raises(ValueError, match="project_id 不能为空"):
use_case.execute("")
mock_repo.list_by_project.assert_not_called()
def test_whitespace_project_id_raises(self, mock_repo):
"""纯空格 project_id 抛出"""
use_case = ListGeneratedVideosUseCase(mock_repo)
with pytest.raises(ValueError, match="project_id 不能为空"):
use_case.execute(" ")
def test_project_id_stripped(self, mock_repo, sample_video):
"""project_id 会被 strip"""
mock_repo.list_by_project.return_value = [sample_video]
use_case = ListGeneratedVideosUseCase(mock_repo)
use_case.execute(" proj_1 ")
mock_repo.list_by_project.assert_called_once_with("proj_1")
class TestListGeneratedVideosPaginatedUseCase:
"""ListGeneratedVideosPaginatedUseCase 测试"""
def test_paginated_default_params(self, mock_repo, sample_video):
"""默认分页参数正确传递"""
mock_repo.list_paginated.return_value = ([sample_video], 1)
use_case = ListGeneratedVideosPaginatedUseCase(mock_repo)
results, total = use_case.execute(user_id="user_1")
assert len(results) == 1
assert total == 1
mock_repo.list_paginated.assert_called_once_with(
user_id="user_1",
project_id=None,
status=None,
review_status=None,
page=1,
page_size=20,
)
def test_page_less_than_1_clamped(self, mock_repo, sample_video):
"""page < 1 被修正为 1"""
mock_repo.list_paginated.return_value = ([sample_video], 1)
use_case = ListGeneratedVideosPaginatedUseCase(mock_repo)
use_case.execute(page=0)
call_kwargs = mock_repo.list_paginated.call_args[1]
assert call_kwargs["page"] == 1
def test_page_size_less_than_1_clamped(self, mock_repo, sample_video):
"""page_size < 1 被修正为 20"""
mock_repo.list_paginated.return_value = ([sample_video], 1)
use_case = ListGeneratedVideosPaginatedUseCase(mock_repo)
use_case.execute(page_size=0)
call_kwargs = mock_repo.list_paginated.call_args[1]
assert call_kwargs["page_size"] == 20
def test_page_size_greater_than_100_clamped(self, mock_repo, sample_video):
"""page_size > 100 被修正为 20"""
mock_repo.list_paginated.return_value = ([sample_video], 1)
use_case = ListGeneratedVideosPaginatedUseCase(mock_repo)
use_case.execute(page_size=200)
call_kwargs = mock_repo.list_paginated.call_args[1]
assert call_kwargs["page_size"] == 20
def test_full_filter_params(self, mock_repo, sample_video):
"""所有过滤参数正确传递"""
mock_repo.list_paginated.return_value = ([sample_video], 1)
use_case = ListGeneratedVideosPaginatedUseCase(mock_repo)
use_case.execute(
user_id="user_1",
project_id="proj_1",
status="completed",
review_status="approved",
page=2,
page_size=50,
)
mock_repo.list_paginated.assert_called_once_with(
user_id="user_1",
project_id="proj_1",
status="completed",
review_status="approved",
page=2,
page_size=50,
)
class TestGetGeneratedVideoUseCase:
"""GetGeneratedVideoUseCase 测试"""
def test_get_existing(self, mock_repo, sample_video):
"""获取存在的视频"""
mock_repo.get.return_value = sample_video
use_case = GetGeneratedVideoUseCase(mock_repo)
result = use_case.execute("video_123")
assert result is not None
assert result.id == "video_123"
def test_get_nonexistent_returns_none(self, mock_repo):
"""获取不存在的视频返回 None"""
mock_repo.get.return_value = None
use_case = GetGeneratedVideoUseCase(mock_repo)
result = use_case.execute("nonexistent")
assert result is None
class TestListGeneratedVideosByTaskUseCase:
"""ListGeneratedVideosByTaskUseCase 测试"""
def test_list_by_task(self, mock_repo, sample_video):
"""按任务ID查询视频"""
mock_repo.list_by_generation_task.return_value = [sample_video]
use_case = ListGeneratedVideosByTaskUseCase(mock_repo)
result = use_case.execute("task_1")
assert len(result) == 1
mock_repo.list_by_generation_task.assert_called_once_with("task_1")
def test_empty_task_id_raises(self, mock_repo):
"""空任务ID抛出"""
use_case = ListGeneratedVideosByTaskUseCase(mock_repo)
with pytest.raises(ValueError, match="generation_task_id 不能为空"):
use_case.execute("")
def test_task_id_stripped(self, mock_repo, sample_video):
"""任务ID被 strip"""
mock_repo.list_by_generation_task.return_value = [sample_video]
use_case = ListGeneratedVideosByTaskUseCase(mock_repo)
use_case.execute(" task_1 ")
mock_repo.list_by_generation_task.assert_called_once_with("task_1")
class TestGetGeneratedVideoDownloadUrlUseCase:
"""GetGeneratedVideoDownloadUrlUseCase 测试"""
def test_get_url_success(self, mock_repo, sample_video):
"""成功获取下载URL"""
mock_repo.get.return_value = sample_video
use_case = GetGeneratedVideoDownloadUrlUseCase(mock_repo)
result = use_case.execute("video_123")
assert result == sample_video.file_url
assert "test.mp4" in result
def test_get_url_nonexistent_returns_none(self, mock_repo):
"""视频不存在返回 None"""
mock_repo.get.return_value = None
use_case = GetGeneratedVideoDownloadUrlUseCase(mock_repo)
result = use_case.execute("nonexistent")
assert result is None
class TestUpdateVideoReviewStatusUseCase:
"""UpdateVideoReviewStatusUseCase 测试"""
def test_update_status_pending_review(self, mock_repo, sample_video):
"""更新为待审核"""
mock_repo.update_review_status.return_value = sample_video
use_case = UpdateVideoReviewStatusUseCase(mock_repo)
result = use_case.execute("video_123", "pending_review")
assert result is not None
mock_repo.update_review_status.assert_called_once_with("video_123", "pending_review")
def test_update_status_approved(self, mock_repo, sample_video):
"""更新为审核通过"""
mock_repo.update_review_status.return_value = sample_video
use_case = UpdateVideoReviewStatusUseCase(mock_repo)
use_case.execute("video_123", "approved")
mock_repo.update_review_status.assert_called_once_with("video_123", "approved")
def test_update_status_rejected(self, mock_repo, sample_video):
"""更新为审核拒绝"""
mock_repo.update_review_status.return_value = sample_video
use_case = UpdateVideoReviewStatusUseCase(mock_repo)
use_case.execute("video_123", "rejected")
mock_repo.update_review_status.assert_called_once_with("video_123", "rejected")
def test_invalid_status_raises(self, mock_repo):
"""无效状态抛出 ValueError"""
use_case = UpdateVideoReviewStatusUseCase(mock_repo)
with pytest.raises(ValueError, match="无效的 review_status"):
use_case.execute("video_123", "invalid_status")
mock_repo.update_review_status.assert_not_called()
def test_empty_video_id_raises(self, mock_repo):
"""空视频ID抛出"""
use_case = UpdateVideoReviewStatusUseCase(mock_repo)
with pytest.raises(ValueError, match="video_id 不能为空"):
use_case.execute("", "approved")
def test_video_id_stripped(self, mock_repo, sample_video):
"""视频ID被 strip"""
mock_repo.update_review_status.return_value = sample_video
use_case = UpdateVideoReviewStatusUseCase(mock_repo)
use_case.execute(" video_123 ", "approved")
mock_repo.update_review_status.assert_called_once_with("video_123", "approved")
class TestGetVideosByIdsUseCase:
"""GetVideosByIdsUseCase 测试"""
def test_get_by_ids(self, mock_repo, sample_video):
"""按ID批量获取"""
video2 = GeneratedVideo.create(
project_id="proj_1",
generation_task_id="task_2",
name="视频2",
file_url="https://oss.example.com/videos/v2.mp4",
)
video2.id = "video_456"
mock_repo.get_by_ids.return_value = [sample_video, video2]
use_case = GetVideosByIdsUseCase(mock_repo)
result = use_case.execute(["video_123", "video_456"])
assert len(result) == 2
mock_repo.get_by_ids.assert_called_once_with(["video_123", "video_456"])
def test_empty_list(self, mock_repo):
"""空ID列表返回空"""
mock_repo.get_by_ids.return_value = []
use_case = GetVideosByIdsUseCase(mock_repo)
result = use_case.execute([])
assert result == []