Funboost 测试规范
SkillAI & modelsUse when writing tests for the funboost framework, running test scripts, or verifying new broker/mixin implementations. Trigger scenarios: writing test scripts, verifying consumer/publisher functionality, AI Agent running funboost scripts. Keywords: test funboost, 写测试, 运行测试, test_frame, regression t
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Funboost 测试规范 skill
What this skill tells your AI
The instructions your AI receives, as published by ydf0509/funboost in .agents/skills/developing-funboost-testing/SKILL.md and read by ahel’s review.
概述
Funboost 使用独立的 Python 脚本作为测试(非 pytest)。核心挑战:consume() 启动后是无限循环,测试必须设定超时或 os._exit() 来终止。
核心原则: 每个测试必须有终止机制——要么外部超时,要么内部 os._exit()。
适用场景
- 为新 broker 实现编写测试
- 验证 mixin/扩展行为
- 运行已有测试脚本
- 修复 bug 后编写回归测试
- AI Agent 需要验证 funboost 代码
测试目录规范
| 类型 | 目录 | 场景 |
|---|---|---|
| AI 编写的 demo/示例 | tests/ai_codes/ai_demos/{子文件夹}/ | AI 写的示例代码(必须新建子文件夹) |
| AI 回归测试 | tests/ai_codes/regression_testing/ | AI 测试框架修改 |
| 人工测试 | test_frame/ | 框架作者的手动测试 |
注意: AI 写 demo 必须在 ai_demos/ 下新建合理的子文件夹,不要直接在 ai_demos/ 根下放脚本。
测试脚本模板
"""测试:[测试内容描述]"""
import os
import time
# PYTHONPATH 必须在运行脚本前通过命令行设置,不要在脚本内设置
# PowerShell: $env:PYTHONPATH="D:\codes\funboost"
# CMD: set PYTHONPATH=D:\codes\funboost
os.environ["LOG_PATH"] = r"D:\pythonlogs\ai_console_outs"
os.environ["PRINT_WRTIE_FILE_NAME"] = "test_feature_xyz_run1"
os.environ["SYS_STD_FILE_NAME"] = "test_feature_xyz_std1"
from funboost import boost, BoosterParams, BrokerEnum
@boost(BoosterParams(
queue_name="test_feature_xyz",
broker_kind=BrokerEnum.SQLITE_QUEUE, # 零配置,适合测试
concurrent_num=5,
qps=10,
))
def test_task(x: int):
print(f"处理 {x},结果 = {x * 2}")
return x * 2
if __name__ == "__main__":
# 发布测试消息
for i in range(10):
test_task.push(i)
# 启动消费
test_task.consume()
# 等待足够时间后自动退出
time.sleep(15)
os._exit(66)
两种运行方式(AI Agent)
方式一:内部 os._exit + 日志文件(推荐)
import os
import time
os.environ["LOG_PATH"] = r"D:\pythonlogs\ai_console_outs"
os.environ["PRINT_WRTIE_FILE_NAME"] = "test_xyz_run1"
os.environ["SYS_STD_FILE_NAME"] = "test_xyz_std1"
# ... 测试代码 ...
time.sleep(15)
os._exit(66)
运行后读取 D:\pythonlogs\ai_console_outs\ 下生成的日志文件查看输出(nb_log 会自动添加日期前缀,如 2026-06-29.0001.test_xyz_run1.print,需模糊搜索匹配)。
重要: 每次运行使用不同的文件名后缀(时间戳或序号),避免读到上次的老日志。
方式二:subprocess.run 外部超时
import subprocess
result = subprocess.run(
['python', 'tests/ai_codes/my_test.py'],
cwd=r'D:\codes\funboost',
timeout=30,
env={**os.environ, 'PYTHONPATH': r'D:\codes\funboost'}
)
脚本无需 os._exit — subprocess 超时后自动终止子进程。
⚠️ 不要使用 cmd /c "timeout /t N & python xxx.py":timeout 命令是先空等 N 秒再启动 python,不会限制 python 运行时长。
超时/休眠时间估算(一般要大于 10 秒):
- 框架启动时间:5-10 秒
- 默认值:
concurrent_num=50,qps=None(不限制) - 不设 qps 时:
实际吞吐量 ≈ concurrent_num / 函数耗时 - 设 qps 时:
实际吞吐量 ≈ min(qps, concurrent_num / 函数耗时) 合理时间 ≈ 框架启动时间(5-10秒) + (消息个数 / 实际吞吐量) + 缓冲时间(2-5秒)- 最大不超过 50 秒
测试验证清单
Broker 测试:
- 消息发布成功(无发布错误)
- 消费者正常启动(无错误)
- 消息被消费(print/日志显示处理结果)
- 正确数量的消息被处理
- ACK 正常工作(消息不会重复出现)
- 重试功能正常(模拟失败时)
Mixin 测试:
- Mixin 初始化成功(
custom_init执行) - 钩子方法触发(前置/后置)
- super() 链正常工作(MRO 不断裂)
-
user_options中的配置被正确读取 - 多个 mixin 组合正常
PYTHONPATH 必须设置
运行任何 funboost 脚本前必须设置 PYTHONPATH = 项目根目录:
# PowerShell
$env:PYTHONPATH="D:\codes\funboost"
# CMD
set PYTHONPATH=D:\codes\funboost
为什么必须设置:
- 解决
import funboost的路径问题 - funboost 启动时通过
importlib.import_module('funboost_config')从sys.path中加载配置文件。 设置 PYTHONPATH 让项目根目录进入sys.path,框架就能找到funboost_config.py并读取 Redis/RabbitMQ 等连接配置。不设则用框架默认值(localhost)。首次运行找不到时会自动生成配置模板。
示例:测试新 Broker
"""测试:TXT 文件 broker"""
import os
import time
# PYTHONPATH 须在命令行设置,脚本内设置无效
os.environ["LOG_PATH"] = r"D:\pythonlogs\ai_console_outs"
os.environ["PRINT_WRTIE_FILE_NAME"] = "test_txt_broker_run1"
os.environ["SYS_STD_FILE_NAME"] = "test_txt_broker_std1"
from funboost import boost, BoosterParams, BrokerEnum
@boost(BoosterParams(
queue_name="test_txt_broker",
broker_kind=BrokerEnum.TXT_FILE,
concurrent_num=3,
qps=5,
))
def txt_task(name: str, value: int):
result = f"{name}={value * 10}"
print(f"[OK] {result}")
return result
if __name__ == "__main__":
# 阶段1:发布
for i in range(5):
txt_task.push(f"item_{i}", value=i)
print(f"已发布 5 条消息")
# 阶段2:消费
txt_task.consume()
# 阶段3:等待并验证
time.sleep(15)
print("测试完成")
os._exit(66)
示例:测试 Mixin
"""测试:自定义监控 mixin"""
import os
import time
# PYTHONPATH 须在命令行设置,脚本内设置无效
os.environ["LOG_PATH"] = r"D:\pythonlogs\ai_console_outs"
os.environ["PRINT_WRTIE_FILE_NAME"] = "test_mixin_run1"
os.environ["SYS_STD_FILE_NAME"] = "test_mixin_std1"
from funboost import boost, BoosterParams, BrokerEnum
from funboost.consumers.base_consumer import AbstractConsumer
class CounterMixin(AbstractConsumer):
def custom_init(self):
super().custom_init()
self._success_count = 0
self._fail_count = 0
def _both_sync_and_aio_frame_custom_record_process_info_func(self, status, kw):
super()._both_sync_and_aio_frame_custom_record_process_info_func(status, kw)
if status.success:
self._success_count += 1
else:
self._fail_count += 1
print(f"[COUNTER] success={self._success_count}, fail={self._fail_count}")
@boost(BoosterParams(
queue_name="test_counter_mixin",
broker_kind=BrokerEnum.SQLITE_QUEUE,
consumer_override_cls=CounterMixin,
concurrent_num=2,
qps=5,
))
def counted_task(x: int):
if x % 3 == 0:
raise ValueError(f"模拟失败 {x}")
return x * 2
if __name__ == "__main__":
for i in range(10):
counted_task.push(i)
counted_task.consume()
time.sleep(20)
os._exit(66)
判断测试是否通过
退出码 66 不代表测试通过! 退出码只说明脚本跑完了 sleep 没有提前崩溃,但无法证明任务是否被正确消费执行。AI 必须读取控制台输出或日志文件,确认:
- 有预期的 print 输出(如函数执行结果)
- 无 Error/Exception 堆栈
- 消费次数与 push 次数一致
相关 Skill
using-funboost-basics— 基础使用入门funboost-troubleshooting— 排错与 FAQ
Signals
- GitHub stars
- 891
- Forks
- 166
- Last commit
- Aug 2026
Advanced
- Catalog kind
- skill
- Gateway key
developing-funboost-testing- Source
- github.com/ydf0509/funboost