1. 删除了 test/unit/external_systems/framework/ 下的废弃空测试目录 2. 修复多处测试断言逻辑、参数传递与测试数据构造 3. 新增日志级别、缓存令牌、流事件等DTO单元测试 4. 补充路由绑定、会话仓储、outbox仓储的测试覆盖 5. 更新测试用例中的异常类型、参数校验与业务逻辑断言
230 lines
6.7 KiB
Python
230 lines
6.7 KiB
Python
"""wizard.py DTO 单元测试。
|
|
|
|
覆盖 ``WizardFieldType`` 枚举与 ``WizardField`` / ``WizardStep`` /
|
|
``WizardConfigPatch`` / ``WizardStepResult`` 的字段赋值、默认值与
|
|
不可变语义。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import dataclasses
|
|
from typing import Any
|
|
|
|
import pytest
|
|
from yuxi.channels.contract.dtos.wizard import (
|
|
WizardConfigPatch,
|
|
WizardField,
|
|
WizardFieldType,
|
|
WizardStep,
|
|
WizardStepResult,
|
|
)
|
|
|
|
pytestmark = pytest.mark.unit
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestWizardFieldType:
|
|
"""向导字段类型枚举测试。"""
|
|
|
|
def test_enum_values_are_correct(self):
|
|
# Arrange
|
|
# Act
|
|
# Assert
|
|
assert WizardFieldType.TEXT == "text"
|
|
assert WizardFieldType.PASSWORD == "password"
|
|
assert WizardFieldType.SELECT == "select"
|
|
assert WizardFieldType.OAUTH == "oauth"
|
|
assert WizardFieldType.WEBHOOK_URL == "webhook_url"
|
|
assert WizardFieldType.CHECKBOX == "checkbox"
|
|
assert WizardFieldType.QR_LOGIN == "qr_login"
|
|
|
|
def test_enum_inherits_from_str(self):
|
|
# Arrange
|
|
# Act
|
|
# Assert
|
|
assert issubclass(WizardFieldType, str)
|
|
assert isinstance(WizardFieldType.TEXT, str)
|
|
|
|
def test_enum_has_seven_members(self):
|
|
# Arrange
|
|
# Act
|
|
members = list(WizardFieldType)
|
|
# Assert
|
|
assert len(members) == 7
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestWizardField:
|
|
"""向导字段 DTO 测试。"""
|
|
|
|
def test_required_fields_are_assigned(self):
|
|
# Arrange
|
|
# Act
|
|
field = WizardField(name="app_id", field_type=WizardFieldType.TEXT)
|
|
# Assert
|
|
assert field.name == "app_id"
|
|
assert field.field_type is WizardFieldType.TEXT
|
|
|
|
def test_defaults_are_correct(self):
|
|
# Arrange
|
|
# Act
|
|
field = WizardField(name="app_id", field_type=WizardFieldType.TEXT)
|
|
# Assert
|
|
assert field.label == ""
|
|
assert field.required is True
|
|
assert field.default is None
|
|
assert field.placeholder == ""
|
|
assert field.help == ""
|
|
assert field.options == ()
|
|
assert field.sensitive is False
|
|
|
|
def test_custom_values_are_assigned(self):
|
|
# Arrange
|
|
# Act
|
|
field = WizardField(
|
|
name="bot_token",
|
|
field_type=WizardFieldType.PASSWORD,
|
|
label="机器人 Token",
|
|
required=True,
|
|
default="",
|
|
placeholder="请输入 Token",
|
|
help="在飞书开放平台获取",
|
|
options=("a", "b"),
|
|
sensitive=True,
|
|
)
|
|
# Assert
|
|
assert field.label == "机器人 Token"
|
|
assert field.default == ""
|
|
assert field.placeholder == "请输入 Token"
|
|
assert field.help == "在飞书开放平台获取"
|
|
assert field.options == ("a", "b")
|
|
assert field.sensitive is True
|
|
|
|
def test_options_is_tuple(self):
|
|
# Arrange
|
|
# Act
|
|
field = WizardField(
|
|
name="env",
|
|
field_type=WizardFieldType.SELECT,
|
|
options=("dev", "prod"),
|
|
)
|
|
# Assert
|
|
assert isinstance(field.options, tuple)
|
|
|
|
def test_is_frozen(self):
|
|
# Arrange
|
|
field = WizardField(name="app_id", field_type=WizardFieldType.TEXT)
|
|
# Act / Assert
|
|
with pytest.raises(dataclasses.FrozenInstanceError):
|
|
field.name = "other" # type: ignore[misc]
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestWizardStep:
|
|
"""向导步骤 DTO 测试。"""
|
|
|
|
def test_required_fields_are_assigned(self):
|
|
# Arrange
|
|
fields = (WizardField(name="app_id", field_type=WizardFieldType.TEXT),)
|
|
# Act
|
|
step = WizardStep(step_id="basic", step_name="基础配置", fields=fields)
|
|
# Assert
|
|
assert step.step_id == "basic"
|
|
assert step.step_name == "基础配置"
|
|
assert step.fields is fields
|
|
|
|
def test_defaults_are_correct(self):
|
|
# Arrange
|
|
# Act
|
|
step = WizardStep(step_id="basic", step_name="基础配置", fields=())
|
|
# Assert
|
|
assert step.description == ""
|
|
assert step.skippable is False
|
|
|
|
def test_fields_is_tuple(self):
|
|
# Arrange
|
|
# Act
|
|
step = WizardStep(
|
|
step_id="basic",
|
|
step_name="基础配置",
|
|
fields=(WizardField(name="a", field_type=WizardFieldType.TEXT),),
|
|
)
|
|
# Assert
|
|
assert isinstance(step.fields, tuple)
|
|
|
|
def test_is_frozen(self):
|
|
# Arrange
|
|
step = WizardStep(step_id="basic", step_name="基础配置", fields=())
|
|
# Act / Assert
|
|
with pytest.raises(dataclasses.FrozenInstanceError):
|
|
step.step_id = "other" # type: ignore[misc]
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestWizardConfigPatch:
|
|
"""向导配置补丁 DTO 测试。"""
|
|
|
|
def test_fields_are_assigned(self):
|
|
# Arrange
|
|
values: dict[str, Any] = {"app_id": "xxx", "token": "yyy"}
|
|
# Act
|
|
patch = WizardConfigPatch(step_id="basic", values=values)
|
|
# Assert
|
|
assert patch.step_id == "basic"
|
|
assert patch.values == values
|
|
|
|
def test_is_frozen(self):
|
|
# Arrange
|
|
patch = WizardConfigPatch(step_id="basic", values={})
|
|
# Act / Assert
|
|
with pytest.raises(dataclasses.FrozenInstanceError):
|
|
patch.step_id = "other" # type: ignore[misc]
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestWizardStepResult:
|
|
"""向导步骤结果 DTO 测试。"""
|
|
|
|
def test_valid_result_defaults(self):
|
|
# Arrange
|
|
# Act
|
|
result = WizardStepResult(step_id="basic", valid=True)
|
|
# Assert
|
|
assert result.errors == ()
|
|
assert result.config_patch is None
|
|
|
|
def test_failed_result_with_errors(self):
|
|
# Arrange
|
|
# Act
|
|
result = WizardStepResult(
|
|
step_id="basic",
|
|
valid=False,
|
|
errors=("app_id is required", "token is required"),
|
|
)
|
|
# Assert
|
|
assert result.valid is False
|
|
assert result.errors == ("app_id is required", "token is required")
|
|
assert result.config_patch is None
|
|
|
|
def test_valid_result_with_config_patch(self):
|
|
# Arrange
|
|
patch = WizardConfigPatch(step_id="basic", values={"app_id": "xxx"})
|
|
# Act
|
|
result = WizardStepResult(step_id="basic", valid=True, config_patch=patch)
|
|
# Assert
|
|
assert result.config_patch is patch
|
|
|
|
def test_errors_is_tuple(self):
|
|
# Arrange
|
|
# Act
|
|
result = WizardStepResult(step_id="basic", valid=False, errors=("err1",))
|
|
# Assert
|
|
assert isinstance(result.errors, tuple)
|
|
|
|
def test_is_frozen(self):
|
|
# Arrange
|
|
result = WizardStepResult(step_id="basic", valid=True)
|
|
# Act / Assert
|
|
with pytest.raises(dataclasses.FrozenInstanceError):
|
|
result.valid = False # type: ignore[misc]
|