ForcePilot/backend/test/unit/channels/contract/dtos/test_wizard.py
Kris 3ae9c0bd21 test: 批量修复与新增单元测试用例,清理废弃测试目录
1.  删除了 test/unit/external_systems/framework/ 下的废弃空测试目录
2.  修复多处测试断言逻辑、参数传递与测试数据构造
3.  新增日志级别、缓存令牌、流事件等DTO单元测试
4.  补充路由绑定、会话仓储、outbox仓储的测试覆盖
5.  更新测试用例中的异常类型、参数校验与业务逻辑断言
2026-07-11 21:43:16 +08:00

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]