"""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