Files
insightflow/backend/test_phase8_task5.py
OpenClaw Bot fe3d64a1d2 fix: auto-fix code issues (cron)
- 修复重复导入/字段
- 修复异常处理
- 修复PEP8格式问题
- 添加类型注解
- 修复缺失的urllib.parse导入
2026-02-28 06:03:09 +08:00

747 lines
26 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
InsightFlow Phase 8 Task 5 - 运营与增长工具测试脚本
测试内容:
1. 用户行为分析(事件追踪、用户画像、转化漏斗、留存率)
2. A/B 测试框架(实验创建、流量分配、结果分析)
3. 邮件营销自动化(模板管理、营销活动、自动化工作流)
4. 推荐系统(推荐计划、推荐码生成、团队激励)
运行方式:
cd /root/.openclaw/workspace/projects/insightflow/backend
python test_phase8_task5.py
"""
import asyncio
import os
import sys
from datetime import datetime, timedelta
from growth_manager import (
EmailTemplateType,
EventType,
ExperimentStatus,
GrowthManager,
TrafficAllocationType,
WorkflowTriggerType,
)
# 添加 backend 目录到路径
backend_dir = os.path.dirname(os.path.abspath(__file__))
if backend_dir not in sys.path:
sys.path.insert(0, backend_dir)
class TestGrowthManager:
"""测试 Growth Manager 功能"""
def __init__(self):
self.manager = GrowthManager()
self.test_tenant_id = "test_tenant_001"
self.test_user_id = "test_user_001"
self.test_results = []
def log(self, message: str, success: bool = True):
"""记录测试结果"""
status = "" if success else ""
print(f"{status} {message}")
self.test_results.append((message, success))
# ==================== 测试用户行为分析 ====================
async def test_track_event(self):
"""测试事件追踪"""
print("\n📊 测试事件追踪...")
try:
event = await self.manager.track_event(
tenant_id=self.test_tenant_id,
user_id=self.test_user_id,
event_type=EventType.PAGE_VIEW,
event_name="dashboard_view",
properties={"page": "/dashboard", "duration": 120},
session_id="session_001",
device_info={"browser": "Chrome", "os": "MacOS"},
referrer="https://google.com",
utm_params={"source": "google", "medium": "organic", "campaign": "summer"},
)
assert event.id is not None
assert event.event_type == EventType.PAGE_VIEW
assert event.event_name == "dashboard_view"
self.log(f"事件追踪成功: {event.id}")
return True
except Exception as e:
self.log(f"事件追踪失败: {e}", success=False)
return False
async def test_track_multiple_events(self):
"""测试追踪多个事件"""
print("\n📊 测试追踪多个事件...")
try:
events = [
(EventType.FEATURE_USE, "entity_extraction", {"entity_count": 5}),
(EventType.FEATURE_USE, "relation_discovery", {"relation_count": 3}),
(EventType.CONVERSION, "upgrade_click", {"plan": "pro"}),
(EventType.SIGNUP, "user_registration", {"source": "referral"}),
]
for event_type, event_name, props in events:
await self.manager.track_event(
tenant_id=self.test_tenant_id,
user_id=self.test_user_id,
event_type=event_type,
event_name=event_name,
properties=props,
)
self.log(f"成功追踪 {len(events)} 个事件")
return True
except Exception as e:
self.log(f"批量事件追踪失败: {e}", success=False)
return False
def test_get_user_profile(self):
"""测试获取用户画像"""
print("\n👤 测试用户画像...")
try:
profile = self.manager.get_user_profile(self.test_tenant_id, self.test_user_id)
if profile:
assert profile.user_id == self.test_user_id
assert profile.total_events >= 0
self.log(f"用户画像获取成功: {profile.user_id}, 事件数: {profile.total_events}")
else:
self.log("用户画像不存在(首次访问)")
return True
except Exception as e:
self.log(f"获取用户画像失败: {e}", success=False)
return False
def test_get_analytics_summary(self):
"""测试获取分析汇总"""
print("\n📈 测试分析汇总...")
try:
summary = self.manager.get_user_analytics_summary(
tenant_id=self.test_tenant_id,
start_date=datetime.now() - timedelta(days=7),
end_date=datetime.now(),
)
assert "unique_users" in summary
assert "total_events" in summary
assert "event_type_distribution" in summary
self.log(f"分析汇总: {summary['unique_users']} 用户, {summary['total_events']} 事件")
return True
except Exception as e:
self.log(f"获取分析汇总失败: {e}", success=False)
return False
def test_create_funnel(self):
"""测试创建转化漏斗"""
print("\n🎯 测试创建转化漏斗...")
try:
funnel = self.manager.create_funnel(
tenant_id=self.test_tenant_id,
name="用户注册转化漏斗",
description="从访问到完成注册的转化流程",
steps=[
{"name": "访问首页", "event_name": "page_view_home"},
{"name": "点击注册", "event_name": "signup_click"},
{"name": "填写信息", "event_name": "signup_form_fill"},
{"name": "完成注册", "event_name": "signup_complete"},
],
created_by="test",
)
assert funnel.id is not None
assert len(funnel.steps) == 4
self.log(f"漏斗创建成功: {funnel.id}")
return funnel.id
except Exception as e:
self.log(f"创建漏斗失败: {e}", success=False)
return None
def test_analyze_funnel(self, funnel_id: str):
"""测试分析漏斗"""
print("\n📉 测试漏斗分析...")
if not funnel_id:
self.log("跳过漏斗分析无漏斗ID")
return False
try:
analysis = self.manager.analyze_funnel(
funnel_id=funnel_id,
period_start=datetime.now() - timedelta(days=30),
period_end=datetime.now(),
)
if analysis:
assert "step_conversions" in analysis.__dict__
self.log(f"漏斗分析完成: 总体转化率 {analysis.overall_conversion:.2%}")
return True
else:
self.log("漏斗分析返回空结果")
return False
except Exception as e:
self.log(f"漏斗分析失败: {e}", success=False)
return False
def test_calculate_retention(self):
"""测试留存率计算"""
print("\n🔄 测试留存率计算...")
try:
retention = self.manager.calculate_retention(
tenant_id=self.test_tenant_id,
cohort_date=datetime.now() - timedelta(days=7),
periods=[1, 3, 7],
)
assert "cohort_date" in retention
assert "retention" in retention
self.log(f"留存率计算完成: 同期群 {retention['cohort_size']} 用户")
return True
except Exception as e:
self.log(f"留存率计算失败: {e}", success=False)
return False
# ==================== 测试 A/B 测试框架 ====================
def test_create_experiment(self):
"""测试创建实验"""
print("\n🧪 测试创建 A/B 测试实验...")
try:
experiment = self.manager.create_experiment(
tenant_id=self.test_tenant_id,
name="首页按钮颜色测试",
description="测试不同按钮颜色对转化率的影响",
hypothesis="蓝色按钮比红色按钮有更高的点击率",
variants=[
{"id": "control", "name": "红色按钮", "is_control": True},
{"id": "variant_a", "name": "蓝色按钮", "is_control": False},
{"id": "variant_b", "name": "绿色按钮", "is_control": False},
],
traffic_allocation=TrafficAllocationType.RANDOM,
traffic_split={"control": 0.34, "variant_a": 0.33, "variant_b": 0.33},
target_audience={"conditions": []},
primary_metric="button_click_rate",
secondary_metrics=["conversion_rate", "bounce_rate"],
min_sample_size=100,
confidence_level=0.95,
created_by="test",
)
assert experiment.id is not None
assert experiment.status == ExperimentStatus.DRAFT
self.log(f"实验创建成功: {experiment.id}")
return experiment.id
except Exception as e:
self.log(f"创建实验失败: {e}", success=False)
return None
def test_list_experiments(self):
"""测试列出实验"""
print("\n📋 测试列出实验...")
try:
experiments = self.manager.list_experiments(self.test_tenant_id)
self.log(f"列出 {len(experiments)} 个实验")
return True
except Exception as e:
self.log(f"列出实验失败: {e}", success=False)
return False
def test_assign_variant(self, experiment_id: str):
"""测试分配变体"""
print("\n🎲 测试分配实验变体...")
if not experiment_id:
self.log("跳过变体分配无实验ID")
return False
try:
# 先启动实验
self.manager.start_experiment(experiment_id)
# 测试多个用户的变体分配
test_users = ["user_001", "user_002", "user_003", "user_004", "user_005"]
assignments = {}
for user_id in test_users:
variant_id = self.manager.assign_variant(
experiment_id=experiment_id,
user_id=user_id,
user_attributes={"user_id": user_id, "segment": "new"},
)
if variant_id:
assignments[user_id] = variant_id
self.log(f"变体分配完成: {len(assignments)} 个用户")
return True
except Exception as e:
self.log(f"变体分配失败: {e}", success=False)
return False
def test_record_experiment_metric(self, experiment_id: str):
"""测试记录实验指标"""
print("\n📊 测试记录实验指标...")
if not experiment_id:
self.log("跳过指标记录无实验ID")
return False
try:
# 模拟记录一些指标
test_data = [
("user_001", "control", 1),
("user_002", "variant_a", 1),
("user_003", "variant_b", 0),
("user_004", "control", 1),
("user_005", "variant_a", 1),
]
for user_id, variant_id, value in test_data:
self.manager.record_experiment_metric(
experiment_id=experiment_id,
variant_id=variant_id,
user_id=user_id,
metric_name="button_click_rate",
metric_value=value,
)
self.log(f"成功记录 {len(test_data)} 条指标")
return True
except Exception as e:
self.log(f"记录指标失败: {e}", success=False)
return False
def test_analyze_experiment(self, experiment_id: str):
"""测试分析实验结果"""
print("\n📈 测试分析实验结果...")
if not experiment_id:
self.log("跳过实验分析无实验ID")
return False
try:
result = self.manager.analyze_experiment(experiment_id)
if "error" not in result:
self.log(f"实验分析完成: {len(result.get('variant_results', {}))} 个变体")
return True
else:
self.log(f"实验分析返回错误: {result['error']}", success=False)
return False
except Exception as e:
self.log(f"实验分析失败: {e}", success=False)
return False
# ==================== 测试邮件营销 ====================
def test_create_email_template(self):
"""测试创建邮件模板"""
print("\n📧 测试创建邮件模板...")
try:
template = self.manager.create_email_template(
tenant_id=self.test_tenant_id,
name="欢迎邮件",
template_type=EmailTemplateType.WELCOME,
subject="欢迎加入 InsightFlow",
html_content="""
<h1>欢迎,{{user_name}}</h1>
<p>感谢您注册 InsightFlow。我们很高兴您能加入我们</p>
<p>您的账户已创建,可以开始使用以下功能:</p>
<ul>
<li>知识图谱构建</li>
<li>智能实体提取</li>
<li>团队协作</li>
</ul>
<p><a href="{{dashboard_url}}">立即开始使用</a></p>
""",
from_name="InsightFlow 团队",
from_email="welcome@insightflow.io",
)
assert template.id is not None
assert template.template_type == EmailTemplateType.WELCOME
self.log(f"邮件模板创建成功: {template.id}")
return template.id
except Exception as e:
self.log(f"创建邮件模板失败: {e}", success=False)
return None
def test_list_email_templates(self):
"""测试列出邮件模板"""
print("\n📧 测试列出邮件模板...")
try:
templates = self.manager.list_email_templates(self.test_tenant_id)
self.log(f"列出 {len(templates)} 个邮件模板")
return True
except Exception as e:
self.log(f"列出邮件模板失败: {e}", success=False)
return False
def test_render_template(self, template_id: str):
"""测试渲染邮件模板"""
print("\n🎨 测试渲染邮件模板...")
if not template_id:
self.log("跳过模板渲染无模板ID")
return False
try:
rendered = self.manager.render_template(
template_id=template_id,
variables={
"user_name": "张三",
"dashboard_url": "https://app.insightflow.io/dashboard",
},
)
if rendered:
assert "subject" in rendered
assert "html" in rendered
self.log(f"模板渲染成功: {rendered['subject']}")
return True
else:
self.log("模板渲染返回空结果", success=False)
return False
except Exception as e:
self.log(f"模板渲染失败: {e}", success=False)
return False
def test_create_email_campaign(self, template_id: str):
"""测试创建邮件营销活动"""
print("\n📮 测试创建邮件营销活动...")
if not template_id:
self.log("跳过创建营销活动无模板ID")
return None
try:
campaign = self.manager.create_email_campaign(
tenant_id=self.test_tenant_id,
name="新用户欢迎活动",
template_id=template_id,
recipient_list=[
{"user_id": "user_001", "email": "user1@example.com"},
{"user_id": "user_002", "email": "user2@example.com"},
{"user_id": "user_003", "email": "user3@example.com"},
],
)
assert campaign.id is not None
assert campaign.recipient_count == 3
self.log(f"营销活动创建成功: {campaign.id}, {campaign.recipient_count} 收件人")
return campaign.id
except Exception as e:
self.log(f"创建营销活动失败: {e}", success=False)
return None
def test_create_automation_workflow(self):
"""测试创建自动化工作流"""
print("\n🤖 测试创建自动化工作流...")
try:
workflow = self.manager.create_automation_workflow(
tenant_id=self.test_tenant_id,
name="新用户欢迎序列",
description="用户注册后自动发送欢迎邮件序列",
trigger_type=WorkflowTriggerType.USER_SIGNUP,
trigger_conditions={"event": "user_signup"},
actions=[
{"type": "send_email", "template_type": "welcome", "delay_hours": 0},
{"type": "send_email", "template_type": "onboarding", "delay_hours": 24},
{"type": "send_email", "template_type": "feature_tips", "delay_hours": 72},
],
)
assert workflow.id is not None
assert workflow.trigger_type == WorkflowTriggerType.USER_SIGNUP
self.log(f"自动化工作流创建成功: {workflow.id}")
return True
except Exception as e:
self.log(f"创建工作流失败: {e}", success=False)
return False
# ==================== 测试推荐系统 ====================
def test_create_referral_program(self):
"""测试创建推荐计划"""
print("\n🎁 测试创建推荐计划...")
try:
program = self.manager.create_referral_program(
tenant_id=self.test_tenant_id,
name="邀请好友奖励计划",
description="邀请好友注册,双方获得积分奖励",
referrer_reward_type="credit",
referrer_reward_value=100.0,
referee_reward_type="credit",
referee_reward_value=50.0,
max_referrals_per_user=10,
referral_code_length=8,
expiry_days=30,
)
assert program.id is not None
assert program.referrer_reward_value == 100.0
self.log(f"推荐计划创建成功: {program.id}")
return program.id
except Exception as e:
self.log(f"创建推荐计划失败: {e}", success=False)
return None
def test_generate_referral_code(self, program_id: str):
"""测试生成推荐码"""
print("\n🔑 测试生成推荐码...")
if not program_id:
self.log("跳过生成推荐码无计划ID")
return None
try:
referral = self.manager.generate_referral_code(
program_id=program_id, referrer_id="referrer_user_001"
)
if referral:
assert referral.referral_code is not None
assert len(referral.referral_code) == 8
self.log(f"推荐码生成成功: {referral.referral_code}")
return referral.referral_code
else:
self.log("生成推荐码返回空结果", success=False)
return None
except Exception as e:
self.log(f"生成推荐码失败: {e}", success=False)
return None
def test_apply_referral_code(self, referral_code: str):
"""测试应用推荐码"""
print("\n✅ 测试应用推荐码...")
if not referral_code:
self.log("跳过应用推荐码(无推荐码)")
return False
try:
success = self.manager.apply_referral_code(
referral_code=referral_code, referee_id="new_user_001"
)
if success:
self.log(f"推荐码应用成功: {referral_code}")
return True
else:
self.log("推荐码应用失败", success=False)
return False
except Exception as e:
self.log(f"应用推荐码失败: {e}", success=False)
return False
def test_get_referral_stats(self, program_id: str):
"""测试获取推荐统计"""
print("\n📊 测试获取推荐统计...")
if not program_id:
self.log("跳过推荐统计无计划ID")
return False
try:
stats = self.manager.get_referral_stats(program_id)
assert "total_referrals" in stats
assert "conversion_rate" in stats
self.log(
f"推荐统计: {stats['total_referrals']} 推荐, {stats['conversion_rate']:.2%} 转化率"
)
return True
except Exception as e:
self.log(f"获取推荐统计失败: {e}", success=False)
return False
def test_create_team_incentive(self):
"""测试创建团队激励"""
print("\n🏆 测试创建团队升级激励...")
try:
incentive = self.manager.create_team_incentive(
tenant_id=self.test_tenant_id,
name="团队升级奖励",
description="团队规模达到5人升级到 Pro 计划可获得折扣",
target_tier="pro",
min_team_size=5,
incentive_type="discount",
incentive_value=20.0, # 20% 折扣
valid_from=datetime.now(),
valid_until=datetime.now() + timedelta(days=90),
)
assert incentive.id is not None
assert incentive.incentive_value == 20.0
self.log(f"团队激励创建成功: {incentive.id}")
return True
except Exception as e:
self.log(f"创建团队激励失败: {e}", success=False)
return False
def test_check_team_incentive_eligibility(self):
"""测试检查团队激励资格"""
print("\n🔍 测试检查团队激励资格...")
try:
incentives = self.manager.check_team_incentive_eligibility(
tenant_id=self.test_tenant_id, current_tier="free", team_size=5
)
self.log(f"找到 {len(incentives)} 个符合条件的激励")
return True
except Exception as e:
self.log(f"检查激励资格失败: {e}", success=False)
return False
# ==================== 测试实时仪表板 ====================
def test_get_realtime_dashboard(self):
"""测试获取实时仪表板"""
print("\n📺 测试实时分析仪表板...")
try:
dashboard = self.manager.get_realtime_dashboard(self.test_tenant_id)
assert "today" in dashboard
assert "recent_events" in dashboard
assert "top_features" in dashboard
today = dashboard["today"]
self.log(
f"实时仪表板: 今日 {today['active_users']} 活跃用户, {today['total_events']} 事件"
)
return True
except Exception as e:
self.log(f"获取实时仪表板失败: {e}", success=False)
return False
# ==================== 运行所有测试 ====================
async def run_all_tests(self):
"""运行所有测试"""
print("=" * 60)
print("🚀 InsightFlow Phase 8 Task 5 - 运营与增长工具测试")
print("=" * 60)
# 用户行为分析测试
print("\n" + "=" * 60)
print("📊 模块 1: 用户行为分析")
print("=" * 60)
await self.test_track_event()
await self.test_track_multiple_events()
self.test_get_user_profile()
self.test_get_analytics_summary()
funnel_id = self.test_create_funnel()
self.test_analyze_funnel(funnel_id)
self.test_calculate_retention()
# A/B 测试框架测试
print("\n" + "=" * 60)
print("🧪 模块 2: A/B 测试框架")
print("=" * 60)
experiment_id = self.test_create_experiment()
self.test_list_experiments()
self.test_assign_variant(experiment_id)
self.test_record_experiment_metric(experiment_id)
self.test_analyze_experiment(experiment_id)
# 邮件营销测试
print("\n" + "=" * 60)
print("📧 模块 3: 邮件营销自动化")
print("=" * 60)
template_id = self.test_create_email_template()
self.test_list_email_templates()
self.test_render_template(template_id)
self.test_create_email_campaign(template_id)
self.test_create_automation_workflow()
# 推荐系统测试
print("\n" + "=" * 60)
print("🎁 模块 4: 推荐系统")
print("=" * 60)
program_id = self.test_create_referral_program()
referral_code = self.test_generate_referral_code(program_id)
self.test_apply_referral_code(referral_code)
self.test_get_referral_stats(program_id)
self.test_create_team_incentive()
self.test_check_team_incentive_eligibility()
# 实时仪表板测试
print("\n" + "=" * 60)
print("📺 模块 5: 实时分析仪表板")
print("=" * 60)
self.test_get_realtime_dashboard()
# 测试总结
print("\n" + "=" * 60)
print("📋 测试总结")
print("=" * 60)
total_tests = len(self.test_results)
passed_tests = sum(1 for _, success in self.test_results if success)
failed_tests = total_tests - passed_tests
print(f"总测试数: {total_tests}")
print(f"通过: {passed_tests}")
print(f"失败: {failed_tests}")
print(f"通过率: {passed_tests / total_tests * 100:.1f}%" if total_tests > 0 else "N/A")
if failed_tests > 0:
print("\n失败的测试:")
for message, success in self.test_results:
if not success:
print(f" - {message}")
print("\n" + "=" * 60)
print("✨ 测试完成!")
print("=" * 60)
async def main():
"""主函数"""
tester = TestGrowthManager()
await tester.run_all_tests()
if __name__ == "__main__":
asyncio.run(main())