Files
wecom_it_smart_desk/tests/test_quick_rules.py
T

208 lines
7.6 KiB
Python
Raw Normal View History

2026-08-11 14:17:39 +08:00
# =============================================================================
# 企微IT智能服务台 — 快速规则单元测试
# =============================================================================
# 用途:测试 QuickRuleService 单元逻辑
# 日期:2026-07-27
# 运行:pytest tests/test_quick_rules.py -v
# =============================================================================
import pytest
from unittest.mock import AsyncMock, MagicMock
from app.models.quick_rule import QuickRule
from app.services.quick_rule_service import QuickRuleService
class TestQuickRuleService:
"""QuickRuleService 单元测试"""
@pytest.fixture(autouse=True)
def reset_cache(self):
"""每个测试前重置缓存"""
QuickRuleService._cache = {
'greeting': [],
'routing_prefilter': {},
'routing_target': {},
}
QuickRuleService._initialized = False
yield
@pytest.mark.asyncio
async def test_load_all_with_greeting_rules(self):
"""测试加载打招呼关键词"""
mock_db = AsyncMock()
mock_rules = [
MagicMock(spec=QuickRule, rule_type='greeting', keyword='你好', category=None, extra_data=None, is_active=True),
MagicMock(spec=QuickRule, rule_type='greeting', keyword='您好', category=None, extra_data=None, is_active=True),
]
mock_result = MagicMock()
mock_result.scalars.return_value.all.return_value = mock_rules
mock_db.execute.return_value = mock_result
await QuickRuleService.load_all(mock_db)
keywords = QuickRuleService.get_greeting_keywords()
assert '你好' in keywords
assert '您好' in keywords
assert len(keywords) == 2
@pytest.mark.asyncio
async def test_load_all_with_routing_keywords(self):
"""测试加载路由关键词"""
mock_db = AsyncMock()
mock_rules = [
MagicMock(spec=QuickRule, rule_type='routing_prefilter', keyword='打印机', category='IT服务', extra_data=None, is_active=True),
MagicMock(spec=QuickRule, rule_type='routing_prefilter', keyword='报销', category='财务', extra_data=None, is_active=True),
]
mock_result = MagicMock()
mock_result.scalars.return_value.all.return_value = mock_rules
mock_db.execute.return_value = mock_result
await QuickRuleService.load_all(mock_db)
keywords = QuickRuleService.get_routing_keywords()
assert keywords['打印机'] == 'IT服务'
assert keywords['报销'] == '财务'
@pytest.mark.asyncio
async def test_load_all_with_routing_targets(self):
"""测试加载路由目标"""
mock_db = AsyncMock()
mock_rules = [
MagicMock(
spec=QuickRule,
rule_type='routing_target',
keyword='机票酒店前台',
category='行政',
extra_data={'service_name': '机票酒店前台', 'url': 'https://example.com'},
is_active=True,
),
]
mock_result = MagicMock()
mock_result.scalars.return_value.all.return_value = mock_rules
mock_db.execute.return_value = mock_result
await QuickRuleService.load_all(mock_db)
targets = QuickRuleService.get_routing_targets()
assert '行政' in targets
assert targets['行政']['service_name'] == '机票酒店前台'
@pytest.mark.asyncio
async def test_load_all_handles_exception(self):
"""测试加载异常处理"""
mock_db = AsyncMock()
mock_db.execute.side_effect = Exception("DB error")
# 不应抛出异常
await QuickRuleService.load_all(mock_db)
# 缓存应保持空
assert QuickRuleService.get_greeting_keywords() == []
def test_check_greeting_true(self):
"""测试 greeting 检测为 true"""
QuickRuleService._cache['greeting'] = ['你好', '您好']
assert QuickRuleService.check_greeting('你好啊') is True
assert QuickRuleService.check_greeting('您好请问') is True
def test_check_greeting_false(self):
"""测试 greeting 检测为 false"""
QuickRuleService._cache['greeting'] = ['你好', '您好']
assert QuickRuleService.check_greeting('打印机坏了') is False
def test_check_greeting_empty_text(self):
"""测试空文本"""
assert QuickRuleService.check_greeting('') is False
assert QuickRuleService.check_greeting(None) is False
def test_check_routing_keyword(self):
"""测试路由关键词检测"""
QuickRuleService._cache['routing_prefilter'] = {
'打印机': 'IT服务',
'报销': '财务',
}
assert QuickRuleService.check_routing_keyword('打印机连不上') is True
assert QuickRuleService.check_routing_keyword('电脑坏了') is False
assert QuickRuleService.check_routing_keyword('报销咨询') is True
def test_get_routing_target_found(self):
"""测试获取存在的路由目标"""
QuickRuleService._cache['routing_target'] = {
'行政': {'service_name': '行政窗口', 'url': 'https://example.com'},
}
target = QuickRuleService.get_routing_target('行政')
assert target is not None
assert target['service_name'] == '行政窗口'
def test_get_routing_target_not_found(self):
"""测试获取不存在的路由目标"""
QuickRuleService._cache['routing_target'] = {
'行政': {'service_name': '行政窗口', 'url': 'https://example.com'},
}
target = QuickRuleService.get_routing_target('不存在的')
assert target is None
def test_get_categories(self):
"""测试获取所有业务分类"""
QuickRuleService._cache['routing_target'] = {
'行政': {},
'财务': {},
'人力资源': {},
}
categories = QuickRuleService.get_categories()
assert set(categories) == {'行政', '财务', '人力资源'}
@pytest.mark.asyncio
async def test_refresh_reloads_cache(self):
"""测试 refresh 重新加载缓存"""
mock_db = AsyncMock()
mock_rules = [
MagicMock(spec=QuickRule, rule_type='greeting', keyword='刷新测试', category=None, extra_data=None, is_active=True),
]
mock_result = MagicMock()
mock_result.scalars.return_value.all.return_value = mock_rules
mock_db.execute.return_value = mock_result
await QuickRuleService.refresh(mock_db)
keywords = QuickRuleService.get_greeting_keywords()
assert '刷新测试' in keywords
class TestQuickRuleDataStructures:
"""QuickRule 数据结构测试"""
def test_quick_rule_model_attributes(self):
"""测试 QuickRule 模型属性"""
rule = QuickRule(
rule_type='greeting',
keyword='你好',
priority=10,
is_active=True,
)
assert rule.rule_type == 'greeting'
assert rule.keyword == '你好'
assert rule.priority == 10
assert rule.is_active is True
def test_to_dict_conversion(self):
"""测试 to_dict 转换"""
from datetime import datetime
rule = QuickRule(
id=1,
rule_type='greeting',
keyword='你好',
priority=10,
is_active=True,
)
rule.created_at = datetime.now()
d = rule.to_dict()
assert d['id'] == 1
assert d['rule_type'] == 'greeting'
assert d['keyword'] == '你好'
assert d['priority'] == 10
assert d['is_active'] is True
assert 'created_at' in d