1. 删除了 test/unit/external_systems/framework/ 下的废弃空测试目录 2. 修复多处测试断言逻辑、参数传递与测试数据构造 3. 新增日志级别、缓存令牌、流事件等DTO单元测试 4. 补充路由绑定、会话仓储、outbox仓储的测试覆盖 5. 更新测试用例中的异常类型、参数校验与业务逻辑断言
123 lines
3.3 KiB
Python
123 lines
3.3 KiB
Python
"""ack.py DTO 单元测试。
|
|
|
|
覆盖 ``AckPolicy`` / ``AckStage`` 枚举与 ``AckDecision`` 的字段赋值、
|
|
不可变语义与 ``__post_init__`` 校验逻辑。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import dataclasses
|
|
|
|
import pytest
|
|
from yuxi.channels.contract.dtos.ack import (
|
|
AckDecision,
|
|
AckPolicy,
|
|
AckStage,
|
|
)
|
|
from yuxi.channels.contract.errors import ValidationError
|
|
|
|
pytestmark = pytest.mark.unit
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestAckPolicy:
|
|
"""ACK 策略枚举测试。"""
|
|
|
|
def test_enum_values_are_correct(self):
|
|
# Arrange
|
|
# Act
|
|
# Assert
|
|
assert AckPolicy.AFTER_RECORD == "after_record"
|
|
assert AckPolicy.AFTER_AGENT_DISPATCH == "after_agent_dispatch"
|
|
assert AckPolicy.AFTER_PERSIST == "after_persist"
|
|
assert AckPolicy.MANUAL == "manual"
|
|
|
|
def test_enum_inherits_from_str(self):
|
|
# Arrange
|
|
# Act
|
|
# Assert
|
|
assert issubclass(AckPolicy, str)
|
|
assert isinstance(AckPolicy.MANUAL, str)
|
|
|
|
def test_enum_has_four_members(self):
|
|
# Arrange
|
|
# Act
|
|
members = list(AckPolicy)
|
|
# Assert
|
|
assert len(members) == 4
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestAckStage:
|
|
"""ACK 阶段枚举测试。"""
|
|
|
|
def test_enum_values_are_correct(self):
|
|
# Arrange
|
|
# Act
|
|
# Assert
|
|
assert AckStage.RECORD == "record"
|
|
assert AckStage.DISPATCH == "dispatch"
|
|
assert AckStage.PERSIST == "persist"
|
|
assert AckStage.MANUAL == "manual"
|
|
|
|
def test_enum_inherits_from_str(self):
|
|
# Arrange
|
|
# Act
|
|
# Assert
|
|
assert issubclass(AckStage, str)
|
|
assert isinstance(AckStage.RECORD, str)
|
|
|
|
def test_enum_has_four_members(self):
|
|
# Arrange
|
|
# Act
|
|
members = list(AckStage)
|
|
# Assert
|
|
assert len(members) == 4
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestAckDecision:
|
|
"""ACK 决策 DTO 测试。"""
|
|
|
|
def test_fields_are_assigned(self):
|
|
# Arrange
|
|
# Act
|
|
decision = AckDecision(decision="ack", stage=AckStage.RECORD)
|
|
# Assert
|
|
assert decision.decision == "ack"
|
|
assert decision.stage is AckStage.RECORD
|
|
assert decision.idempotency_key is None
|
|
|
|
def test_with_idempotency_key(self):
|
|
# Arrange
|
|
# Act
|
|
decision = AckDecision(
|
|
decision="nack",
|
|
stage=AckStage.DISPATCH,
|
|
idempotency_key="idem-1",
|
|
)
|
|
# Assert
|
|
assert decision.idempotency_key == "idem-1"
|
|
|
|
@pytest.mark.parametrize("action", ["ack", "nack", "retry", "pending"])
|
|
def test_valid_decisions(self, action):
|
|
# Arrange
|
|
# Act
|
|
decision = AckDecision(decision=action, stage=AckStage.RECORD)
|
|
# Assert
|
|
assert decision.decision == action
|
|
|
|
def test_invalid_decision_raises_validation_error(self):
|
|
# Arrange
|
|
# Act / Assert - decision 不在合法取值集合中
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
AckDecision(decision="invalid", stage=AckStage.RECORD) # type: ignore[arg-type]
|
|
assert exc_info.value.field == "decision"
|
|
|
|
def test_is_frozen(self):
|
|
# Arrange
|
|
decision = AckDecision(decision="ack", stage=AckStage.RECORD)
|
|
# Act / Assert
|
|
with pytest.raises(dataclasses.FrozenInstanceError):
|
|
decision.decision = "nack" # type: ignore[misc]
|