新增覆盖以下模块的单元测试: 1. 核心契约与校验函数 2. 持久化层工作单元与ORM映射 3. 运行时处理器注册表 4. 业务用例工具类(退避、抖动、Cron计算) 5. 基础设施容器装配 6. 框架内置清理处理器(运行日志、幂等记录) 7. 测试共享Fixture与桩实现
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
|