Files
xiaoxia-saas/tests/unit/test_tts_job_use_cases.py
CI Bot 3921a657e8
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Successful in 52s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 1m56s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m7s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 2m7s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 54s
CI/CD Pipeline / Validate - Code Quality (push) Failing after 3m20s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 6m27s
CI/CD Pipeline / Unit Tests (push) Failing after 8m24s
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 16m1s
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m14s
CI/CD Pipeline / Integration Tests (push) Successful in 3m28s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 21s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1m26s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m34s
style: auto-format with black + isort + prettier
2026-07-24 08:47:07 +00:00

247 lines
7.8 KiB
Python
Executable File

"""TTS Job Use Cases 单元测试"""
from __future__ import annotations
from unittest.mock import MagicMock
import pytest
from packages.application.tts_job.exceptions import TTSJobNotFoundError
from packages.application.tts_job.use_cases import (
CreateTTSJobUseCase,
DeleteTTSJobUseCase,
GetTTSJobStatusUseCase,
GetTTSJobUseCase,
ListTTSJobsUseCase,
)
from packages.domain.tts_job import TTSJob, TTSJobStatus
@pytest.fixture
def mock_repo():
return MagicMock()
@pytest.fixture
def sample_job():
return TTSJob.create(
user_id="user_001",
input_text="测试文本",
voice_id="voice_001",
voice_model="cosyvoice",
project_id="proj_001",
sample_rate=22050,
format="mp3",
max_retries=3,
)
class TestCreateTTSJobUseCase:
"""创建 TTS 任务用例测试"""
def test_create_success(self, mock_repo, sample_job):
"""创建成功"""
mock_repo.create.return_value = sample_job
use_case = CreateTTSJobUseCase(mock_repo)
result = use_case.execute(
user_id="user_001",
input_text="测试文本",
voice_id="voice_001",
voice_model="cosyvoice",
project_id="proj_001",
)
assert result is not None
assert result.user_id == "user_001"
assert result.input_text == "测试文本"
assert result.status == TTSJobStatus.PENDING
mock_repo.create.assert_called_once()
def test_create_with_default_params(self, mock_repo):
"""使用默认参数创建"""
mock_repo.create.side_effect = lambda x: x
use_case = CreateTTSJobUseCase(mock_repo)
result = use_case.execute(user_id="user_001", input_text="hello")
assert result.voice_id == ""
assert result.voice_model == ""
assert result.sample_rate == 22050
assert result.format == "mp3"
assert result.max_retries == 3
def test_create_with_metadata(self, mock_repo):
"""创建时携带 metadata"""
mock_repo.create.side_effect = lambda x: x
use_case = CreateTTSJobUseCase(mock_repo)
result = use_case.execute(
user_id="user_001",
input_text="test",
metadata={"source": "api", "priority": "high"},
)
assert result.metadata["source"] == "api"
assert result.metadata["priority"] == "high"
def test_create_with_voice_clone_profile(self, mock_repo):
"""使用音色克隆档案创建"""
mock_repo.create.side_effect = lambda x: x
use_case = CreateTTSJobUseCase(mock_repo)
result = use_case.execute(
user_id="user_001",
input_text="test",
voice_clone_profile_id="clone_001",
)
assert result.voice_clone_profile_id == "clone_001"
class TestListTTSJobsUseCase:
"""列出 TTS 任务用例测试"""
def test_list_success(self, mock_repo, sample_job):
"""列出任务成功"""
mock_repo.list_by_user.return_value = [sample_job]
mock_repo.count_by_user.return_value = 1
use_case = ListTTSJobsUseCase(mock_repo)
items, total = use_case.execute(user_id="user_001")
assert len(items) == 1
assert total == 1
mock_repo.list_by_user.assert_called_once_with("user_001", status=None, limit=50, offset=0)
def test_list_with_status_filter(self, mock_repo):
"""按状态过滤"""
mock_repo.list_by_user.return_value = []
mock_repo.count_by_user.return_value = 0
use_case = ListTTSJobsUseCase(mock_repo)
items, total = use_case.execute(user_id="user_001", status="completed")
assert total == 0
mock_repo.list_by_user.assert_called_once_with("user_001", status="completed", limit=50, offset=0)
mock_repo.count_by_user.assert_called_once_with("user_001", status="completed")
def test_list_with_pagination(self, mock_repo):
"""分页参数正确传递"""
mock_repo.list_by_user.return_value = []
mock_repo.count_by_user.return_value = 0
use_case = ListTTSJobsUseCase(mock_repo)
use_case.execute(user_id="user_001", skip=10, limit=20)
mock_repo.list_by_user.assert_called_once_with("user_001", status=None, limit=20, offset=10)
def test_list_empty(self, mock_repo):
"""空列表"""
mock_repo.list_by_user.return_value = []
mock_repo.count_by_user.return_value = 0
use_case = ListTTSJobsUseCase(mock_repo)
items, total = use_case.execute(user_id="user_001")
assert items == []
assert total == 0
class TestGetTTSJobUseCase:
"""获取 TTS 任务详情用例测试"""
def test_get_success(self, mock_repo, sample_job):
"""获取成功"""
mock_repo.get.return_value = sample_job
use_case = GetTTSJobUseCase(mock_repo)
result = use_case.execute(job_id=sample_job.id, user_id="user_001")
assert result.id == sample_job.id
mock_repo.get.assert_called_once_with(sample_job.id)
def test_get_not_found(self, mock_repo):
"""任务不存在"""
mock_repo.get.return_value = None
use_case = GetTTSJobUseCase(mock_repo)
with pytest.raises(TTSJobNotFoundError):
use_case.execute(job_id="nonexistent", user_id="user_001")
def test_get_wrong_user(self, mock_repo, sample_job):
"""用户不匹配"""
mock_repo.get.return_value = sample_job # user_001
use_case = GetTTSJobUseCase(mock_repo)
with pytest.raises(TTSJobNotFoundError):
use_case.execute(job_id=sample_job.id, user_id="other_user")
class TestGetTTSJobStatusUseCase:
"""查询 TTS 任务状态用例测试"""
def test_get_status_success(self, mock_repo, sample_job):
"""获取状态成功"""
mock_repo.get.return_value = sample_job
use_case = GetTTSJobStatusUseCase(mock_repo)
result = use_case.execute(job_id=sample_job.id, user_id="user_001")
assert result.status == TTSJobStatus.PENDING
def test_get_status_not_found(self, mock_repo):
"""任务不存在抛异常"""
mock_repo.get.return_value = None
use_case = GetTTSJobStatusUseCase(mock_repo)
with pytest.raises(TTSJobNotFoundError):
use_case.execute(job_id="nonexistent", user_id="user_001")
def test_get_status_wrong_user(self, mock_repo, sample_job):
"""用户不匹配抛异常"""
mock_repo.get.return_value = sample_job
use_case = GetTTSJobStatusUseCase(mock_repo)
with pytest.raises(TTSJobNotFoundError):
use_case.execute(job_id=sample_job.id, user_id="other_user")
class TestDeleteTTSJobUseCase:
"""删除 TTS 任务用例测试"""
def test_delete_success(self, mock_repo, sample_job):
"""删除成功"""
mock_repo.get.return_value = sample_job
mock_repo.delete.return_value = True
use_case = DeleteTTSJobUseCase(mock_repo)
result = use_case.execute(job_id=sample_job.id, user_id="user_001")
assert result is True
mock_repo.delete.assert_called_once_with(sample_job.id)
def test_delete_not_found(self, mock_repo):
"""任务不存在返回 False"""
mock_repo.get.return_value = None
use_case = DeleteTTSJobUseCase(mock_repo)
result = use_case.execute(job_id="nonexistent", user_id="user_001")
assert result is False
mock_repo.delete.assert_not_called()
def test_delete_wrong_user(self, mock_repo, sample_job):
"""用户不匹配返回 False"""
mock_repo.get.return_value = sample_job
use_case = DeleteTTSJobUseCase(mock_repo)
result = use_case.execute(job_id=sample_job.id, user_id="other_user")
assert result is False
mock_repo.delete.assert_not_called()