test(wave100): 40 unit tests for 3 application layer modules (milestone)
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 22s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 41s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m7s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m21s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 30s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 28s
CI/CD Pipeline / Validate - Code Quality (pull_request) Failing after 2m12s
AI Code Review / AI Code Review (pull_request) Successful in 1m9s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m0s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m7s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m2s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m38s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 3m30s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m17s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Has been cancelled
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 14s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 22s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 41s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m7s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m21s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 30s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 28s
CI/CD Pipeline / Validate - Code Quality (pull_request) Failing after 2m12s
AI Code Review / AI Code Review (pull_request) Successful in 1m9s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m0s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m7s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m2s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m38s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 3m30s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m17s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Has been cancelled
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 14s
Milestone wave #100 — cleaning up zero-test application modules: - generated_videos.py: 8 UseCases fully covered (25 tests) - ListGeneratedVideosUseCase: 4 tests - ListGeneratedVideosPaginatedUseCase: 7 tests (page clamp / page_size clamp / filters) - GetGeneratedVideoUseCase: 2 tests - ListGeneratedVideosByTaskUseCase: 3 tests - GetGeneratedVideoDownloadUrlUseCase: 2 tests - UpdateVideoReviewStatusUseCase: 7 tests (3 valid statuses + validation) - GetVideosByIdsUseCase: 2 tests - assets.py: 6 tests (CreateAssetCommand + ListAssets + CreateAsset) - asset_libraries.py: 5 tests (Command + List + Create) Total: 40 tests across 3 modules
This commit is contained in:
Executable
+499
@@ -0,0 +1,499 @@
|
||||
"""Application 层零测试模块合集 — 第100波里程碑。
|
||||
|
||||
覆盖:
|
||||
- packages/application/generated_videos.py (8个UseCase)
|
||||
- packages/application/assets.py (ListAssets + CreateAsset)
|
||||
- packages/application/asset_libraries.py (ListLibraries + CreateLibrary)
|
||||
|
||||
策略: Mock repository,测参数校验 + 委托行为
|
||||
"""
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
from packages.application.asset_libraries import (
|
||||
CreateAssetLibraryCommand,
|
||||
CreateAssetLibraryUseCase,
|
||||
ListAssetLibrariesUseCase,
|
||||
)
|
||||
from packages.application.assets import (
|
||||
CreateAssetCommand,
|
||||
CreateAssetUseCase,
|
||||
ListAssetsUseCase,
|
||||
)
|
||||
from packages.application.generated_videos import (
|
||||
GetGeneratedVideoDownloadUrlUseCase,
|
||||
GetGeneratedVideoUseCase,
|
||||
GetVideosByIdsUseCase,
|
||||
ListGeneratedVideosByTaskUseCase,
|
||||
ListGeneratedVideosPaginatedUseCase,
|
||||
ListGeneratedVideosUseCase,
|
||||
UpdateVideoReviewStatusUseCase,
|
||||
)
|
||||
from packages.domain import AssetLibraryKind, AssetStatus, ClassificationStatus, GeneratedVideo
|
||||
|
||||
# ── generated_videos.py ────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
class TestListGeneratedVideosUseCase:
|
||||
def test_success(self):
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.list_by_project.return_value = [MagicMock(spec=GeneratedVideo)]
|
||||
use_case = ListGeneratedVideosUseCase(mock_repo)
|
||||
|
||||
result = use_case.execute("proj1")
|
||||
|
||||
assert len(result) == 1
|
||||
mock_repo.list_by_project.assert_called_once_with("proj1")
|
||||
|
||||
def test_strips_project_id(self):
|
||||
mock_repo = MagicMock()
|
||||
use_case = ListGeneratedVideosUseCase(mock_repo)
|
||||
|
||||
use_case.execute(" proj1 ")
|
||||
|
||||
mock_repo.list_by_project.assert_called_once_with("proj1")
|
||||
|
||||
def test_empty_project_id_raises(self):
|
||||
mock_repo = MagicMock()
|
||||
use_case = ListGeneratedVideosUseCase(mock_repo)
|
||||
|
||||
with pytest.raises(ValueError, match="project_id 不能为空"):
|
||||
use_case.execute("")
|
||||
|
||||
def test_whitespace_project_id_raises(self):
|
||||
mock_repo = MagicMock()
|
||||
use_case = ListGeneratedVideosUseCase(mock_repo)
|
||||
|
||||
with pytest.raises(ValueError, match="project_id 不能为空"):
|
||||
use_case.execute(" \t ")
|
||||
|
||||
|
||||
class TestListGeneratedVideosPaginatedUseCase:
|
||||
def test_default_params(self):
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.list_paginated.return_value = ([], 0)
|
||||
use_case = ListGeneratedVideosPaginatedUseCase(mock_repo)
|
||||
|
||||
result, total = use_case.execute()
|
||||
|
||||
assert total == 0
|
||||
assert result == []
|
||||
mock_repo.list_paginated.assert_called_once_with(
|
||||
user_id=None,
|
||||
project_id=None,
|
||||
status=None,
|
||||
review_status=None,
|
||||
page=1,
|
||||
page_size=20,
|
||||
)
|
||||
|
||||
def test_page_below_1_clamps_to_1(self):
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.list_paginated.return_value = ([], 0)
|
||||
use_case = ListGeneratedVideosPaginatedUseCase(mock_repo)
|
||||
|
||||
use_case.execute(page=0)
|
||||
|
||||
mock_repo.list_paginated.assert_called_once()
|
||||
call_kwargs = mock_repo.list_paginated.call_args.kwargs
|
||||
assert call_kwargs["page"] == 1
|
||||
|
||||
def test_negative_page_clamps(self):
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.list_paginated.return_value = ([], 0)
|
||||
use_case = ListGeneratedVideosPaginatedUseCase(mock_repo)
|
||||
|
||||
use_case.execute(page=-5)
|
||||
|
||||
assert mock_repo.list_paginated.call_args.kwargs["page"] == 1
|
||||
|
||||
def test_page_size_zero_clamps(self):
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.list_paginated.return_value = ([], 0)
|
||||
use_case = ListGeneratedVideosPaginatedUseCase(mock_repo)
|
||||
|
||||
use_case.execute(page_size=0)
|
||||
|
||||
assert mock_repo.list_paginated.call_args.kwargs["page_size"] == 20
|
||||
|
||||
def test_page_size_over_100_clamps(self):
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.list_paginated.return_value = ([], 0)
|
||||
use_case = ListGeneratedVideosPaginatedUseCase(mock_repo)
|
||||
|
||||
use_case.execute(page_size=200)
|
||||
|
||||
assert mock_repo.list_paginated.call_args.kwargs["page_size"] == 20
|
||||
|
||||
def test_page_size_50_ok(self):
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.list_paginated.return_value = ([], 0)
|
||||
use_case = ListGeneratedVideosPaginatedUseCase(mock_repo)
|
||||
|
||||
use_case.execute(page_size=50)
|
||||
|
||||
assert mock_repo.list_paginated.call_args.kwargs["page_size"] == 50
|
||||
|
||||
def test_with_all_filters(self):
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.list_paginated.return_value = ([], 0)
|
||||
use_case = ListGeneratedVideosPaginatedUseCase(mock_repo)
|
||||
|
||||
use_case.execute(
|
||||
user_id="u1",
|
||||
project_id="p1",
|
||||
status="completed",
|
||||
review_status="approved",
|
||||
page=2,
|
||||
page_size=10,
|
||||
)
|
||||
|
||||
mock_repo.list_paginated.assert_called_once_with(
|
||||
user_id="u1",
|
||||
project_id="p1",
|
||||
status="completed",
|
||||
review_status="approved",
|
||||
page=2,
|
||||
page_size=10,
|
||||
)
|
||||
|
||||
|
||||
class TestGetGeneratedVideoUseCase:
|
||||
def test_found(self):
|
||||
mock_repo = MagicMock()
|
||||
expected = MagicMock(spec=GeneratedVideo)
|
||||
mock_repo.get.return_value = expected
|
||||
use_case = GetGeneratedVideoUseCase(mock_repo)
|
||||
|
||||
result = use_case.execute("vid1")
|
||||
|
||||
assert result == expected
|
||||
mock_repo.get.assert_called_once_with("vid1")
|
||||
|
||||
def test_not_found(self):
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.get.return_value = None
|
||||
use_case = GetGeneratedVideoUseCase(mock_repo)
|
||||
|
||||
result = use_case.execute("vid1")
|
||||
|
||||
assert result is None
|
||||
|
||||
|
||||
class TestListGeneratedVideosByTaskUseCase:
|
||||
def test_success(self):
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.list_by_generation_task.return_value = [MagicMock()]
|
||||
use_case = ListGeneratedVideosByTaskUseCase(mock_repo)
|
||||
|
||||
result = use_case.execute("task1")
|
||||
|
||||
assert len(result) == 1
|
||||
mock_repo.list_by_generation_task.assert_called_once_with("task1")
|
||||
|
||||
def test_strips_task_id(self):
|
||||
mock_repo = MagicMock()
|
||||
use_case = ListGeneratedVideosByTaskUseCase(mock_repo)
|
||||
|
||||
use_case.execute(" task1 ")
|
||||
|
||||
mock_repo.list_by_generation_task.assert_called_once_with("task1")
|
||||
|
||||
def test_empty_task_id_raises(self):
|
||||
mock_repo = MagicMock()
|
||||
use_case = ListGeneratedVideosByTaskUseCase(mock_repo)
|
||||
|
||||
with pytest.raises(ValueError, match="generation_task_id 不能为空"):
|
||||
use_case.execute("")
|
||||
|
||||
|
||||
class TestGetGeneratedVideoDownloadUrlUseCase:
|
||||
def test_found(self):
|
||||
mock_repo = MagicMock()
|
||||
mock_item = MagicMock()
|
||||
mock_item.file_url = "https://cdn/v.mp4"
|
||||
mock_repo.get.return_value = mock_item
|
||||
use_case = GetGeneratedVideoDownloadUrlUseCase(mock_repo)
|
||||
|
||||
result = use_case.execute("vid1")
|
||||
|
||||
assert result == "https://cdn/v.mp4"
|
||||
|
||||
def test_not_found_returns_none(self):
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.get.return_value = None
|
||||
use_case = GetGeneratedVideoDownloadUrlUseCase(mock_repo)
|
||||
|
||||
result = use_case.execute("vid1")
|
||||
|
||||
assert result is None
|
||||
|
||||
|
||||
class TestUpdateVideoReviewStatusUseCase:
|
||||
def test_pending_review(self):
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.update_review_status.return_value = MagicMock()
|
||||
use_case = UpdateVideoReviewStatusUseCase(mock_repo)
|
||||
|
||||
use_case.execute("vid1", "pending_review")
|
||||
|
||||
mock_repo.update_review_status.assert_called_once_with("vid1", "pending_review")
|
||||
|
||||
def test_approved(self):
|
||||
mock_repo = MagicMock()
|
||||
use_case = UpdateVideoReviewStatusUseCase(mock_repo)
|
||||
|
||||
use_case.execute("vid1", "approved")
|
||||
|
||||
mock_repo.update_review_status.assert_called_once_with("vid1", "approved")
|
||||
|
||||
def test_rejected(self):
|
||||
mock_repo = MagicMock()
|
||||
use_case = UpdateVideoReviewStatusUseCase(mock_repo)
|
||||
|
||||
use_case.execute("vid1", "rejected")
|
||||
|
||||
mock_repo.update_review_status.assert_called_once_with("vid1", "rejected")
|
||||
|
||||
def test_strips_video_id(self):
|
||||
mock_repo = MagicMock()
|
||||
use_case = UpdateVideoReviewStatusUseCase(mock_repo)
|
||||
|
||||
use_case.execute(" vid1 ", "approved")
|
||||
|
||||
mock_repo.update_review_status.assert_called_once_with("vid1", "approved")
|
||||
|
||||
def test_empty_video_id_raises(self):
|
||||
mock_repo = MagicMock()
|
||||
use_case = UpdateVideoReviewStatusUseCase(mock_repo)
|
||||
|
||||
with pytest.raises(ValueError, match="video_id 不能为空"):
|
||||
use_case.execute("", "approved")
|
||||
|
||||
def test_invalid_status_raises(self):
|
||||
mock_repo = MagicMock()
|
||||
use_case = UpdateVideoReviewStatusUseCase(mock_repo)
|
||||
|
||||
with pytest.raises(ValueError, match="无效的 review_status"):
|
||||
use_case.execute("vid1", "invalid_status")
|
||||
|
||||
def test_not_found_returns_none(self):
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.update_review_status.return_value = None
|
||||
use_case = UpdateVideoReviewStatusUseCase(mock_repo)
|
||||
|
||||
result = use_case.execute("vid1", "approved")
|
||||
|
||||
assert result is None
|
||||
|
||||
|
||||
class TestGetVideosByIdsUseCase:
|
||||
def test_success(self):
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.get_by_ids.return_value = [MagicMock(), MagicMock()]
|
||||
use_case = GetVideosByIdsUseCase(mock_repo)
|
||||
|
||||
result = use_case.execute(["id1", "id2", "id3"])
|
||||
|
||||
assert len(result) == 2
|
||||
mock_repo.get_by_ids.assert_called_once_with(["id1", "id2", "id3"])
|
||||
|
||||
def test_empty_list(self):
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.get_by_ids.return_value = []
|
||||
use_case = GetVideosByIdsUseCase(mock_repo)
|
||||
|
||||
result = use_case.execute([])
|
||||
|
||||
assert result == []
|
||||
mock_repo.get_by_ids.assert_called_once_with([])
|
||||
|
||||
|
||||
# ── assets.py ──────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
class TestCreateAssetCommand:
|
||||
def test_minimal(self):
|
||||
cmd = CreateAssetCommand(
|
||||
project_id="p1",
|
||||
library_id="l1",
|
||||
name="test.mp4",
|
||||
storage_key="k",
|
||||
mime_type="video/mp4",
|
||||
)
|
||||
assert cmd.project_id == "p1"
|
||||
assert cmd.library_id == "l1"
|
||||
assert cmd.name == "test.mp4"
|
||||
assert cmd.storage_key == "k"
|
||||
assert cmd.mime_type == "video/mp4"
|
||||
assert cmd.file_size == 0
|
||||
assert cmd.status == AssetStatus.UPLOADING
|
||||
assert cmd.classification_status == ClassificationStatus.PENDING
|
||||
|
||||
def test_full(self):
|
||||
cmd = CreateAssetCommand(
|
||||
project_id="p1",
|
||||
library_id="l1",
|
||||
name="test.mp4",
|
||||
storage_key="k",
|
||||
mime_type="video/mp4",
|
||||
metadata={"k": "v"},
|
||||
file_size=1024,
|
||||
duration=10.0,
|
||||
width=1920,
|
||||
height=1080,
|
||||
fps=30.0,
|
||||
codec="h264",
|
||||
status=AssetStatus.READY,
|
||||
quality_score=0.9,
|
||||
uploaded_by_user_id="u1",
|
||||
)
|
||||
assert cmd.file_size == 1024
|
||||
assert cmd.duration == 10.0
|
||||
assert cmd.status == AssetStatus.READY
|
||||
assert cmd.quality_score == 0.9
|
||||
|
||||
|
||||
class TestListAssetsUseCase:
|
||||
def test_success(self):
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.find_by_library.return_value = []
|
||||
use_case = ListAssetsUseCase(mock_repo)
|
||||
|
||||
result = use_case.execute("lib1")
|
||||
|
||||
assert result == []
|
||||
mock_repo.find_by_library.assert_called_once_with("lib1")
|
||||
|
||||
def test_strips_library_id(self):
|
||||
mock_repo = MagicMock()
|
||||
use_case = ListAssetsUseCase(mock_repo)
|
||||
|
||||
use_case.execute(" lib1 ")
|
||||
|
||||
mock_repo.find_by_library.assert_called_once_with("lib1")
|
||||
|
||||
def test_empty_library_id_raises(self):
|
||||
mock_repo = MagicMock()
|
||||
use_case = ListAssetsUseCase(mock_repo)
|
||||
|
||||
with pytest.raises(ValueError, match="library_id 不能为空"):
|
||||
use_case.execute("")
|
||||
|
||||
|
||||
class TestCreateAssetUseCase:
|
||||
def test_creates_asset_via_repo(self):
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.create.return_value = MagicMock()
|
||||
use_case = CreateAssetUseCase(mock_repo)
|
||||
|
||||
cmd = CreateAssetCommand(
|
||||
project_id="p1",
|
||||
library_id="l1",
|
||||
name="test.mp4",
|
||||
storage_key="videos/t.mp4",
|
||||
mime_type="video/mp4",
|
||||
file_size=1024,
|
||||
)
|
||||
result = use_case.execute(cmd)
|
||||
|
||||
assert result is not None
|
||||
mock_repo.create.assert_called_once()
|
||||
created_asset = mock_repo.create.call_args[0][0]
|
||||
assert created_asset.project_id == "p1"
|
||||
assert created_asset.name == "test.mp4"
|
||||
assert created_asset.file_size == 1024
|
||||
assert created_asset.status == AssetStatus.UPLOADING
|
||||
|
||||
def test_asset_create_validation_propagates(self):
|
||||
mock_repo = MagicMock()
|
||||
use_case = CreateAssetUseCase(mock_repo)
|
||||
|
||||
cmd = CreateAssetCommand(
|
||||
project_id="p1",
|
||||
library_id="l1",
|
||||
name="",
|
||||
storage_key="k",
|
||||
mime_type="video/mp4",
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError, match="素材名称不能为空"):
|
||||
use_case.execute(cmd)
|
||||
|
||||
|
||||
# ── asset_libraries.py ────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
class TestCreateAssetLibraryCommand:
|
||||
def test_creation(self):
|
||||
cmd = CreateAssetLibraryCommand(
|
||||
project_id="p1",
|
||||
name="我的库",
|
||||
kind=AssetLibraryKind.VIDEO,
|
||||
)
|
||||
assert cmd.project_id == "p1"
|
||||
assert cmd.name == "我的库"
|
||||
assert cmd.kind == AssetLibraryKind.VIDEO
|
||||
|
||||
|
||||
class TestListAssetLibrariesUseCase:
|
||||
def test_success(self):
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.find_by_project.return_value = []
|
||||
use_case = ListAssetLibrariesUseCase(mock_repo)
|
||||
|
||||
result = use_case.execute("p1")
|
||||
|
||||
assert result == []
|
||||
mock_repo.find_by_project.assert_called_once_with("p1")
|
||||
|
||||
def test_strips_project_id(self):
|
||||
mock_repo = MagicMock()
|
||||
use_case = ListAssetLibrariesUseCase(mock_repo)
|
||||
|
||||
use_case.execute(" p1 ")
|
||||
|
||||
mock_repo.find_by_project.assert_called_once_with("p1")
|
||||
|
||||
def test_empty_project_id_raises(self):
|
||||
mock_repo = MagicMock()
|
||||
use_case = ListAssetLibrariesUseCase(mock_repo)
|
||||
|
||||
with pytest.raises(ValueError, match="project_id 不能为空"):
|
||||
use_case.execute("")
|
||||
|
||||
|
||||
class TestCreateAssetLibraryUseCase:
|
||||
def test_creates_library_via_repo(self):
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.create.return_value = MagicMock()
|
||||
use_case = CreateAssetLibraryUseCase(mock_repo)
|
||||
|
||||
cmd = CreateAssetLibraryCommand(
|
||||
project_id="p1",
|
||||
name="视频库",
|
||||
kind=AssetLibraryKind.VIDEO,
|
||||
)
|
||||
result = use_case.execute(cmd)
|
||||
|
||||
assert result is not None
|
||||
mock_repo.create.assert_called_once()
|
||||
created = mock_repo.create.call_args[0][0]
|
||||
assert created.project_id == "p1"
|
||||
assert created.name == "视频库"
|
||||
assert created.kind == AssetLibraryKind.VIDEO
|
||||
|
||||
def test_validation_propagates(self):
|
||||
mock_repo = MagicMock()
|
||||
use_case = CreateAssetLibraryUseCase(mock_repo)
|
||||
|
||||
cmd = CreateAssetLibraryCommand(
|
||||
project_id="p1",
|
||||
name="",
|
||||
kind=AssetLibraryKind.VIDEO,
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError, match="素材库名称不能为空"):
|
||||
use_case.execute(cmd)
|
||||
Reference in New Issue
Block a user