This commit is contained in:
chenxiangtong
2026-03-26 17:38:47 +08:00
commit a05ce6e07e
54 changed files with 5779 additions and 0 deletions

View File

@@ -0,0 +1,206 @@
from types import SimpleNamespace
from unittest.mock import AsyncMock, MagicMock
import pytest
from src.services import SubscriptionService
@pytest.fixture
def mock_repo() -> MagicMock:
repo = MagicMock()
repo.subscribe_subject = MagicMock(return_value=True)
repo.remove_subscription = MagicMock(return_value=True)
repo.find_group_subscription_candidates = MagicMock(return_value=[])
return repo
@pytest.fixture
def mock_service() -> MagicMock:
service = MagicMock()
service.search_subjects = AsyncMock()
service.get_subject_details = AsyncMock()
service.get_calendar = AsyncMock()
service.get_latest_episode = AsyncMock()
service.get_subject_base64image = AsyncMock()
return service
@pytest.mark.asyncio
async def test_subscribe_success(mock_repo, mock_service) -> None:
mock_service.search_subjects.return_value = {"data": [{"id": 123}]}
mock_service.get_subject_details.return_value = {
"id": 123,
"name": "Test Anime",
"name_cn": "测试番剧",
"date": "2024-01-01",
"eps": 12,
}
mock_service.get_calendar.return_value = [{"items": [{"id": 123}]}]
sub_service = SubscriptionService(
repository=mock_repo, service=mock_service, config_manager=MagicMock()
)
result = await sub_service.subscribe("group_1", "Test Anime")
assert "成功订阅《测试番剧》" in result
mock_repo.subscribe_subject.assert_called_once_with(
group_id="group_1",
subject_id="123",
name="测试番剧",
air_date="2024-01-01",
total_episodes=12,
)
@pytest.mark.asyncio
async def test_unsubscribe_local_single_match_success(mock_repo, mock_service) -> None:
mock_repo.find_group_subscription_candidates.return_value = [
SimpleNamespace(subject_id="123", name="测试番剧")
]
sub_service = SubscriptionService(
repository=mock_repo, service=mock_service, config_manager=MagicMock()
)
result = await sub_service.unsubscribe("group_1", "")
assert "已成功取消订阅《测试番剧》" in result
mock_repo.find_group_subscription_candidates.assert_called_once_with(
group_id="group_1", keyword="", limit=6
)
mock_repo.remove_subscription.assert_called_once_with("group_1", "123")
mock_service.search_subjects.assert_not_called()
mock_service.get_subject_details.assert_not_called()
mock_service.get_calendar.assert_not_called()
@pytest.mark.asyncio
async def test_unsubscribe_local_no_match(mock_repo, mock_service) -> None:
mock_repo.find_group_subscription_candidates.return_value = []
sub_service = SubscriptionService(
repository=mock_repo, service=mock_service, config_manager=MagicMock()
)
result = await sub_service.unsubscribe("group_1", "不存在")
assert "未找到与「不存在」匹配的本群订阅番剧" in result
mock_repo.remove_subscription.assert_not_called()
mock_service.search_subjects.assert_not_called()
mock_service.get_subject_details.assert_not_called()
mock_service.get_calendar.assert_not_called()
@pytest.mark.asyncio
async def test_unsubscribe_local_multi_match_returns_candidates(
mock_repo, mock_service
) -> None:
mock_repo.find_group_subscription_candidates.return_value = [
SimpleNamespace(subject_id="1", name="进击的巨人"),
SimpleNamespace(subject_id="2", name="进击!巨人中学"),
SimpleNamespace(subject_id="3", name="巨人族的新娘"),
]
sub_service = SubscriptionService(
repository=mock_repo, service=mock_service, config_manager=MagicMock()
)
result = await sub_service.unsubscribe("group_1", "巨人")
assert "匹配到多个已订阅番剧" in result
assert "1. 进击的巨人 (ID: 1)" in result
assert "2. 进击!巨人中学 (ID: 2)" in result
assert "3. 巨人族的新娘 (ID: 3)" in result
mock_repo.remove_subscription.assert_not_called()
mock_service.search_subjects.assert_not_called()
mock_service.get_subject_details.assert_not_called()
mock_service.get_calendar.assert_not_called()
@pytest.mark.asyncio
async def test_unsubscribe_local_remove_failed(mock_repo, mock_service) -> None:
mock_repo.find_group_subscription_candidates.return_value = [
SimpleNamespace(subject_id="123", name="测试番剧")
]
mock_repo.remove_subscription.return_value = False
sub_service = SubscriptionService(
repository=mock_repo, service=mock_service, config_manager=MagicMock()
)
result = await sub_service.unsubscribe("group_1", "")
assert "取消订阅失败:你可能并没有订阅《测试番剧》" in result
mock_repo.remove_subscription.assert_called_once_with("group_1", "123")
@pytest.mark.asyncio
async def test_get_subscribe_candidates_multi_match(mock_repo, mock_service) -> None:
mock_service.search_subjects.return_value = {
"data": [
{"id": 1, "name_cn": "进击的巨人"},
{"id": 2, "name": "进击!巨人中学"},
{"id": 1, "name_cn": "进击的巨人"},
{"name_cn": "无ID条目"},
]
}
sub_service = SubscriptionService(
repository=mock_repo, service=mock_service, config_manager=MagicMock()
)
error_msg, candidates = await sub_service.get_subscribe_candidates("巨人", 5)
assert error_msg is None
assert candidates == [
{"subject_id": "1", "name": "进击的巨人"},
{"subject_id": "2", "name": "进击!巨人中学"},
]
mock_service.search_subjects.assert_awaited_once_with(
keyword="巨人",
limit=5,
subject_type=[2],
subject_tags=None,
)
@pytest.mark.asyncio
async def test_subscribe_by_subject_id_success(mock_repo, mock_service) -> None:
mock_service.get_subject_details.return_value = {
"id": 456,
"name": "Test Name",
"name_cn": "测试番剧2",
"date": "2025-01-01",
"eps": 24,
}
mock_service.get_calendar.return_value = [{"items": [{"id": 456}]}]
sub_service = SubscriptionService(
repository=mock_repo, service=mock_service, config_manager=MagicMock()
)
result = await sub_service.subscribe_by_subject_id("group_1", "456")
assert "✅ 成功订阅《测试番剧2》" in result
mock_repo.subscribe_subject.assert_called_once_with(
group_id="group_1",
subject_id="456",
name="测试番剧2",
air_date="2025-01-01",
total_episodes=24,
)
@pytest.mark.asyncio
async def test_subscribe_by_subject_id_not_in_calendar(mock_repo, mock_service) -> None:
mock_service.get_subject_details.return_value = {
"id": 789,
"name": "Not In Calendar",
"name_cn": "未放送番剧",
"date": "2025-06-01",
"eps": 12,
}
mock_service.get_calendar.return_value = [{"items": [{"id": 456}]}]
sub_service = SubscriptionService(
repository=mock_repo, service=mock_service, config_manager=MagicMock()
)
result = await sub_service.subscribe_by_subject_id("group_1", "789")
assert "不在当前的每日放送列表中" in result
mock_repo.subscribe_subject.assert_not_called()