上周帮朋友改一个库存扣减的 bug,他写的逻辑是「下单时直接减库存」,结果高并发下库存变成负数。问题不在语法,而在逻辑——没人提前验证它在各种情况下是否真的成立。
逻辑不是跑通就万事大吉
很多新手以为编译通过、能输出结果,程序就算“对了”。但现实里,逻辑漏洞往往藏在边界、并发、异常路径里。比如:
用户重复点击提交按钮,订单创建了两遍;
时间跨午夜,优惠券有效期判断出错;
数据库查不到数据,程序直接空指针崩溃,而不是走兜底逻辑。
手写测试用例:最朴实也最管用
不用框架,打开编辑器,对着函数自己列几组输入和预期输出。比如一个计算折扣的函数:
def calc_discount(price, coupon_type):
if coupon_type == "new_user":
return max(0, price - 50)
elif coupon_type == "vip":
return price * 0.8
else:
return price那就手动试:price=100, coupon_type="new_user" → 应得 50;price=30, coupon_type="new_user" → 应得 0(不能负);price=200, coupon_type="vip" → 应得 160。边写边跑,比光看代码靠谱得多。
打印关键路径 + 日志断点
调试器不是只用来“暂停”,而是用来确认「程序是不是真按你想的走」。比如处理支付回调,加几行日志:
log.info("收到回调,order_id=%s, status=%s", order_id, pay_status)
if not order_exists(order_id):
log.warn("订单不存在,丢弃回调")
return
if pay_status == "success":
log.info("准备更新订单状态为已支付")
update_order_status(order_id, "paid")上线前用测试回调触发几次,翻日志一看,路径对不对、有没有漏掉的 else 分支,一目了然。
用断言守住底线
在关键位置埋 assert,不是为了生产报错,而是开发阶段给自己提个醒。比如处理用户等级升级:
def upgrade_level(user_id):
level = get_current_level(user_id)
new_level = level + 1
assert new_level <= 10, f"等级不能超过10,当前{level}"
save_level(user_id, new_level)本地跑测试时一旦越界,立刻打断,比等线上报警再排查快十倍。
让真实数据说话
拿生产导出的脱敏订单数据(比如最近1000条),喂给新写的统计函数,和旧版结果对比。不求全对,但明显偏差大的(比如总数差 20%),马上回头查逻辑分支是否漏了某种状态。
逻辑验证不是玄学,也不是测试工程师的专属活儿。写完 if,想想 else 干啥;写完循环,问问会不会死循环;写完调第三方接口,猜猜它挂了你接得住吗——这些念头,就是最朴素的逻辑验证。