第17章:测试策略:单元测试、集成测试、压力测试、混沌工程
说实话,做量化系统这么多年,我见过太多「上线即崩」的惨案了。
有一次,我们一个做市商策略刚上线,行情一波动,整个系统直接挂了。后来复盘发现,就是一个边界条件没测到。嗯,从那以后,我对测试策略的重视程度,直接拉满。
今天咱们聊聊结构化产品做市商系统的测试策略。说白了,就是怎么保证你的系统在真实战场上不拉胯。
17.1 单元测试:把每个零件都拧紧
单元测试,我个人的习惯是「能测尽测」。尤其是那些核心计算逻辑,比如定价引擎、风险计算、订单管理。
你想想看,一个定价公式里,如果有个符号写反了,集成测试可能半天都查不出来。但单元测试,几秒钟就能定位。
举个例子,我们有个计算期权理论价格的函数:
// 伪代码示例
func TestOptionPricing(t *testing.T) {
// 正常情况
price := CalculateOptionPrice(100, 105, 0.3, 0.05, 30)
assert.InDelta(t, 2.5, price, 0.01)
// 边界:行权价等于现价
price = CalculateOptionPrice(100, 100, 0.3, 0.05, 30)
assert.Greater(t, price, 0.0)
// 边界:剩余天数为0
price = CalculateOptionPrice(100, 105, 0.3, 0.05, 0)
assert.Equal(t, 0.0, price)
}
我在项目中遇到过一个问题:有个同事写了个波动率计算函数,没测输入为0的情况。结果生产环境里,某只股票停牌了,波动率算出来是NaN,整个风险模块全崩了。
所以,单元测试的覆盖率,我建议至少到80%以上。尤其是那些「看起来不会出问题」的地方,往往就是坑。
17.2 集成测试:看零件能不能一起转
单元测试过了,不代表系统能跑通。集成测试,就是看各个模块之间能不能正常协作。
比如,行情模块收到数据后,能不能正确传给定价引擎?定价引擎算完价格,订单模块能不能正确发出指令?
我一般会做这么几类集成测试:
- 行情到定价的链路: 模拟行情数据,看定价引擎输出是否合理
- 定价到风控的链路: 检查风控模块能否正确拦截超限订单
- 订单到交易所的链路: 模拟交易所响应,看订单状态更新是否正确
这里有个坑:集成测试的环境,最好跟生产环境保持一致。我曾经因为测试环境用的数据库版本不一样,结果上线后才发现有个SQL语法不兼容。嗯,那晚的加班餐,味道真不怎么样。
17.3 压力测试:看看系统能扛多大风浪
做市商系统,最怕的就是行情剧烈波动。平时风平浪静,一到关键时刻就掉链子,那可就惨了。
压力测试,说白了就是模拟极端行情,看看系统能不能扛住。
我常用的压力测试场景:
- 高并发行情: 模拟每秒1000笔以上的行情更新,看系统延迟
- 大量订单: 同时提交数百笔订单,看订单处理速度
- 资源耗尽: 模拟内存、CPU、网络带宽接近极限的情况
举个例子,我们用JMeter做过一个压力测试:
// 压力测试配置示例
Thread Group:
- Number of Threads: 500
- Ramp-up Period: 10 seconds
- Loop Count: 100
HTTP Request:
- Protocol: TCP
- Port: 8080
- Path: /api/order/submit
Assertions:
- Response Time < 100ms
- Error Rate < 0.1%
我记得有一次压力测试,系统在500并发下直接OOM了。查了半天,发现是一个缓存没设置过期时间,导致内存暴涨。从那以后,我每次压测都会盯着内存曲线看。
17.4 混沌工程:主动搞破坏,提前发现弱点
混沌工程,听起来很玄乎,其实就是「故意搞破坏」。在可控的环境里,模拟各种故障,看看系统能不能自我修复。
我刚开始接触混沌工程时,觉得这玩意儿有点多余。直到有一次,我们一个依赖的Redis集群挂了,整个做市系统停了10分钟。嗯,从那以后,我成了混沌工程的忠实粉丝。
常见的混沌实验:
- 杀死一个服务实例: 看负载均衡能否自动切换
- 模拟网络延迟: 看系统能否优雅降级
- 让数据库主库宕机: 看能否自动切换到从库
- 注入CPU压力: 看系统能否限流保护
我们团队用Chaos Monkey做过一个实验:随机杀死一个订单处理服务实例。结果发现,虽然系统能自动恢复,但恢复期间有少量订单丢失了。这个问题,要不是混沌工程,可能永远发现不了。
17.5 测试策略的整体框架
说了这么多,咱们用一张图来总结一下测试策略的整体框架:
从这张图可以看出来,测试策略是一个金字塔结构。底层是单元测试,覆盖最广、成本最低。越往上,测试范围越大,但成本也越高。
我个人建议的投入比例是:单元测试占60%,集成测试占25%,压力测试占10%,混沌工程占5%。当然,具体比例要看你的系统规模和风险承受能力。
好了,关于测试策略,今天就聊到这儿。记住一句话:测试不是为了证明系统没问题,而是为了发现系统有问题。越早发现,成本越低。