105 lines
3.0 KiB
Python
105 lines
3.0 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
必需配置缺失检测属性测试
|
||
|
||
**Validates: Requirements 4.4**
|
||
|
||
Property 4: 必需配置缺失检测
|
||
对于任意必需配置项,当所有配置层级(.env、.env.local、环境变量、CLI)
|
||
均未提供该项时,配置加载器应抛出错误,且错误信息中包含该缺失配置项的名称。
|
||
"""
|
||
import pytest
|
||
from hypothesis import given, settings
|
||
from hypothesis.strategies import lists, from_regex
|
||
|
||
|
||
def validate_required_config(required_keys: list[str], config: dict) -> None:
|
||
"""验证必需配置项是否全部存在且非空。
|
||
|
||
Args:
|
||
required_keys: 必需配置项名称列表
|
||
config: 实际配置字典
|
||
|
||
Raises:
|
||
ValueError: 当存在缺失或空值的必需配置项时,
|
||
错误信息包含所有缺失项名称
|
||
"""
|
||
missing = [k for k in required_keys if k not in config or not config[k]]
|
||
if missing:
|
||
raise ValueError(f"缺失必需配置项: {', '.join(missing)}")
|
||
|
||
|
||
# 合法配置项名称:大写字母开头,后跟大写字母/数字/下划线
|
||
_key_strategy = from_regex(r"[A-Z][A-Z0-9_]{0,19}", fullmatch=True)
|
||
|
||
|
||
@given(
|
||
required_keys=lists(
|
||
_key_strategy,
|
||
min_size=1,
|
||
max_size=5,
|
||
unique=True,
|
||
)
|
||
)
|
||
@settings(max_examples=100)
|
||
def test_missing_required_config_raises_error(required_keys: list[str]):
|
||
"""
|
||
Property 4: 空配置字典 -> 抛出 ValueError 且包含缺失项名称
|
||
|
||
**Validates: Requirements 4.4**
|
||
"""
|
||
empty_config: dict = {}
|
||
|
||
with pytest.raises(ValueError, match="缺失必需配置项"):
|
||
validate_required_config(required_keys, empty_config)
|
||
|
||
# 额外验证:错误信息包含每个缺失项名称
|
||
try:
|
||
validate_required_config(required_keys, empty_config)
|
||
except ValueError as exc:
|
||
msg = str(exc)
|
||
for key in required_keys:
|
||
assert key in msg, (
|
||
f"错误信息应包含缺失配置项 '{key}',但实际信息为: {msg}"
|
||
)
|
||
|
||
|
||
@given(
|
||
required_keys=lists(
|
||
_key_strategy,
|
||
min_size=1,
|
||
max_size=5,
|
||
unique=True,
|
||
)
|
||
)
|
||
@settings(max_examples=100)
|
||
def test_empty_value_treated_as_missing(required_keys: list[str]):
|
||
"""
|
||
Property 4: 空值视为缺失 -> 抛出 ValueError
|
||
|
||
**Validates: Requirements 4.4**
|
||
"""
|
||
config_with_empty = {k: "" for k in required_keys}
|
||
|
||
with pytest.raises(ValueError, match="缺失必需配置项"):
|
||
validate_required_config(required_keys, config_with_empty)
|
||
|
||
|
||
@given(
|
||
required_keys=lists(
|
||
_key_strategy,
|
||
min_size=1,
|
||
max_size=5,
|
||
unique=True,
|
||
)
|
||
)
|
||
@settings(max_examples=100)
|
||
def test_all_required_present_no_error(required_keys: list[str]):
|
||
"""
|
||
Property 4 反向验证:所有必需项均提供非空值时不抛异常
|
||
|
||
**Validates: Requirements 4.4**
|
||
"""
|
||
config_complete = {k: f"value_for_{k}" for k in required_keys}
|
||
validate_required_config(required_keys, config_complete)
|