165 lines
6.7 KiB
Python
165 lines
6.7 KiB
Python
|
|
"""infrastructure/container.py 装配容器单元测试。
|
|||
|
|
|
|||
|
|
覆盖 ``yuxi.scheduler.infrastructure.container`` 模块的两个 factory 函数:
|
|||
|
|
- ``create_scheduler_service``:api 进程请求级 factory(handler_registry=None)
|
|||
|
|
- ``create_worker_scheduler_service``:worker 进程请求级 factory(完整 runtime)
|
|||
|
|
|
|||
|
|
验证装配结果 ``SchedulerService`` 实例的依赖注入正确性。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
from unittest.mock import MagicMock, patch
|
|||
|
|
|
|||
|
|
import pytest
|
|||
|
|
|
|||
|
|
from yuxi.scheduler.framework.runtime import HandlerRegistry, RuntimeServices
|
|||
|
|
from yuxi.scheduler.infrastructure.container import (
|
|||
|
|
SchedulerService,
|
|||
|
|
create_scheduler_service,
|
|||
|
|
create_worker_scheduler_service,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
pytestmark = pytest.mark.unit
|
|||
|
|
|
|||
|
|
|
|||
|
|
@pytest.fixture
|
|||
|
|
def db_session() -> MagicMock:
|
|||
|
|
"""提供 MagicMock 模拟 AsyncSession。"""
|
|||
|
|
return MagicMock()
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ─── create_scheduler_service ─────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
|
|||
|
|
@pytest.mark.unit
|
|||
|
|
class TestCreateSchedulerService:
|
|||
|
|
def test_returns_scheduler_service_instance(self, db_session: MagicMock):
|
|||
|
|
# Arrange & Act
|
|||
|
|
with patch("yuxi.scheduler.infrastructure.container.app_config"):
|
|||
|
|
service = create_scheduler_service(db_session)
|
|||
|
|
# Assert
|
|||
|
|
assert isinstance(service, SchedulerService)
|
|||
|
|
|
|||
|
|
def test_handler_registry_is_none(self, db_session: MagicMock):
|
|||
|
|
# Arrange & Act - api 进程 handler_registry=None
|
|||
|
|
with patch("yuxi.scheduler.infrastructure.container.app_config"):
|
|||
|
|
service = create_scheduler_service(db_session)
|
|||
|
|
# Assert
|
|||
|
|
assert service._runtime.handler_registry is None
|
|||
|
|
|
|||
|
|
def test_arq_pool_defaults_to_none(self, db_session: MagicMock):
|
|||
|
|
with patch("yuxi.scheduler.infrastructure.container.app_config"):
|
|||
|
|
service = create_scheduler_service(db_session)
|
|||
|
|
assert service._runtime.arq_pool is None
|
|||
|
|
|
|||
|
|
def test_arq_pool_passed_through(self, db_session: MagicMock):
|
|||
|
|
# Arrange
|
|||
|
|
pool = MagicMock()
|
|||
|
|
# Act
|
|||
|
|
with patch("yuxi.scheduler.infrastructure.container.app_config"):
|
|||
|
|
service = create_scheduler_service(db_session, arq_pool=pool)
|
|||
|
|
# Assert
|
|||
|
|
assert service._runtime.arq_pool is pool
|
|||
|
|
|
|||
|
|
def test_repos_injected(self, db_session: MagicMock):
|
|||
|
|
with patch("yuxi.scheduler.infrastructure.container.app_config"):
|
|||
|
|
service = create_scheduler_service(db_session)
|
|||
|
|
# Assert - 4 个仓储实例被注入
|
|||
|
|
assert service._repos.task is not None
|
|||
|
|
assert service._repos.run_log is not None
|
|||
|
|
assert service._repos.run_log_daily is not None
|
|||
|
|
assert service._repos.idempotency is not None
|
|||
|
|
|
|||
|
|
def test_uow_injected(self, db_session: MagicMock):
|
|||
|
|
with patch("yuxi.scheduler.infrastructure.container.app_config"):
|
|||
|
|
service = create_scheduler_service(db_session)
|
|||
|
|
assert service._uow is not None
|
|||
|
|
|
|||
|
|
def test_config_injected(self, db_session: MagicMock):
|
|||
|
|
with patch("yuxi.scheduler.infrastructure.container.app_config") as mock_config:
|
|||
|
|
service = create_scheduler_service(db_session)
|
|||
|
|
assert service._runtime.config is mock_config
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ─── create_worker_scheduler_service ──────────────────────────────────────
|
|||
|
|
|
|||
|
|
|
|||
|
|
@pytest.mark.unit
|
|||
|
|
class TestCreateWorkerSchedulerService:
|
|||
|
|
def test_returns_scheduler_service_instance(self, db_session: MagicMock):
|
|||
|
|
# Arrange
|
|||
|
|
registry = HandlerRegistry()
|
|||
|
|
pool = MagicMock()
|
|||
|
|
# Act
|
|||
|
|
with patch("yuxi.scheduler.infrastructure.container.app_config"):
|
|||
|
|
service = create_worker_scheduler_service(
|
|||
|
|
db_session, handler_registry=registry, arq_pool=pool
|
|||
|
|
)
|
|||
|
|
# Assert
|
|||
|
|
assert isinstance(service, SchedulerService)
|
|||
|
|
|
|||
|
|
def test_handler_registry_injected(self, db_session: MagicMock):
|
|||
|
|
registry = HandlerRegistry()
|
|||
|
|
pool = MagicMock()
|
|||
|
|
with patch("yuxi.scheduler.infrastructure.container.app_config"):
|
|||
|
|
service = create_worker_scheduler_service(
|
|||
|
|
db_session, handler_registry=registry, arq_pool=pool
|
|||
|
|
)
|
|||
|
|
assert service._runtime.handler_registry is registry
|
|||
|
|
|
|||
|
|
def test_arq_pool_injected(self, db_session: MagicMock):
|
|||
|
|
registry = HandlerRegistry()
|
|||
|
|
pool = MagicMock()
|
|||
|
|
with patch("yuxi.scheduler.infrastructure.container.app_config"):
|
|||
|
|
service = create_worker_scheduler_service(
|
|||
|
|
db_session, handler_registry=registry, arq_pool=pool
|
|||
|
|
)
|
|||
|
|
assert service._runtime.arq_pool is pool
|
|||
|
|
|
|||
|
|
def test_repos_injected(self, db_session: MagicMock):
|
|||
|
|
registry = HandlerRegistry()
|
|||
|
|
pool = MagicMock()
|
|||
|
|
with patch("yuxi.scheduler.infrastructure.container.app_config"):
|
|||
|
|
service = create_worker_scheduler_service(
|
|||
|
|
db_session, handler_registry=registry, arq_pool=pool
|
|||
|
|
)
|
|||
|
|
assert service._repos.task is not None
|
|||
|
|
assert service._repos.run_log is not None
|
|||
|
|
assert service._repos.run_log_daily is not None
|
|||
|
|
assert service._repos.idempotency is not None
|
|||
|
|
|
|||
|
|
def test_uow_injected(self, db_session: MagicMock):
|
|||
|
|
registry = HandlerRegistry()
|
|||
|
|
pool = MagicMock()
|
|||
|
|
with patch("yuxi.scheduler.infrastructure.container.app_config"):
|
|||
|
|
service = create_worker_scheduler_service(
|
|||
|
|
db_session, handler_registry=registry, arq_pool=pool
|
|||
|
|
)
|
|||
|
|
assert service._uow is not None
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ─── RuntimeServices 装配 ─────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
|
|||
|
|
@pytest.mark.unit
|
|||
|
|
class TestRuntimeServicesAssembly:
|
|||
|
|
def test_api_runtime_has_none_registry(self, db_session: MagicMock):
|
|||
|
|
with patch("yuxi.scheduler.infrastructure.container.app_config"):
|
|||
|
|
service = create_scheduler_service(db_session)
|
|||
|
|
# Assert - RuntimeServices dataclass 字段正确
|
|||
|
|
assert isinstance(service._runtime, RuntimeServices)
|
|||
|
|
assert service._runtime.handler_registry is None
|
|||
|
|
|
|||
|
|
def test_worker_runtime_has_registry_and_pool(self, db_session: MagicMock):
|
|||
|
|
registry = HandlerRegistry()
|
|||
|
|
pool = MagicMock()
|
|||
|
|
with patch("yuxi.scheduler.infrastructure.container.app_config"):
|
|||
|
|
service = create_worker_scheduler_service(
|
|||
|
|
db_session, handler_registry=registry, arq_pool=pool
|
|||
|
|
)
|
|||
|
|
assert isinstance(service._runtime, RuntimeServices)
|
|||
|
|
assert service._runtime.handler_registry is registry
|
|||
|
|
assert service._runtime.arq_pool is pool
|