刚入行时我以为,高级测试工程师厉害在“会得多”——更牛的框架、更花哨的 mock、更高级的压测。我拼命学这些,以为学会就能升级。
后来我跟一群真正的测试老兵共事。我发现他们的用例,一点都不炫。
但奇怪的是——需求变了一轮又一轮,别人用例改崩了,他们的用例永远稳稳跑通,每次都能精准截住回归 Bug。
后来我才明白:初级和高级的差距,根本不在“会多少工具”,而在 7 个习惯。跟用 Pytest 还是 JUnit 没关系,它们决定的就三件事——漏测多不多、报错好不好查、用例别人接手要花多久看懂。
下面这 7 条,每一条配一个真实业务场景,一起来康康。
习惯1、先把“不满足条件”的情况拦在外面
场景:你要测试“退款”功能。前提是:订单已支付、而且还没退过。
新手常常这么写——像套娃一样,每个条件套一层:
def 测试退款():
订单 = 创建订单()
if 订单存在:
支付(订单)
if 订单状态 == "已支付":
if 订单没退过:
退款(订单)
assert 退款成功
else:
报错("已退过")
else:
报错("没支付")
else:
报错("没订单")
刚写完觉得没问题。但后来产品说要加“风控检查”,你再套一层;再过两周加“优惠券退回”,又套一层。最后真正干活的“退款”那行代码被埋在最里面,你自己过两个月回来看都得懵。
高级测试怎么干?反过来——把不满足条件的全部先踢出去:
def 测试退款():
订单 = 创建订单()
assert 订单 is not None, "订单都没生成,跑啥?"
支付(订单)
assert 订单状态 == "已支付", "没付钱不能退"
assert 订单没退过, "重复退了,兄弟"
# 走到这里,说明前面都OK,放心测
退款(订单)
assert 退款成功
TIPS: 前置条件先卡死,主逻辑顶格写,谁看都清楚。
习惯2、给测试用例起个备注名字
场景:你要测“给有效订阅用户发续费提醒”。
新手经常写:
def test_1():
...
半年后你自己看都不知道这是测什么。更可怕的是,跑完自动化测试,报告里一堆 test_1、test_2,失败了都不知道是哪个业务场景挂了。
高级测试这么写名字——直接用业务场景当名字:
def test_给有效订阅发续费提醒_应该成功():
...
def test_给过期订阅发续费提醒_应该跳过():
...
TIPS: 用例名就是你的报告,要让人一眼看懂测的是什么业务。
习惯3、在“外部依赖”外面包一层,别硬编码
场景:你的测试要模拟微信支付的回调。
新手直接硬写:
def 测试微信回调():
请求数据 = {
"user_name": "张三",
"status": "ACTIVE"
}
调用接口(请求数据)
assert 返回成功
一个用例这么写没事,十个用例都这么写就有事了。突然有一天微信把字段名 user_name 改成了 userName,你的十个用例全挂,一个一个改到吐血。
高级测试怎么做?在外面包一个“翻译函数”:
def 造微信数据(用户):
return {
"user_name": 用户.名字, # 如果微信改名,我只改这一行
"status": 用户.状态
}
def 测试微信回调():
请求数据 = 造微信数据(测试用户)
调用接口(请求数据)
assert 返回成功
TIPS: 外部的东西变数大,用一层函数隔开,你的测试代码就稳了。
习惯4、别让“不可能存在”的订单状态出现在测试里
场景:你要测试退款,需要各种状态的订单。
新手图省事,用个字典,所有字段都可填可不填:
订单 = {
"id": None,
"状态": "已支付",
"已退款": False
}
因为全是可选的,你随便乱组合都行。结果有一天你手滑造了一个“已退款”但“状态”还是“已支付”的怪物订单,测试居然跑过了,但线上真实逻辑根本不会出现这种组合,结果漏测了一个严重 Bug。
高级测试会怎么干?用工厂函数,只生成“合法的”订单:
def 造已支付订单():
return 订单(id=生成ID(), 状态="已支付", 已退款=False)
def 造已退款订单():
return 订单(id=生成ID(), 状态="已退款", 已退款=True)
这样你测试退款时,只能传“已支付订单”,你传“已退款订单”的话,写代码时就会报错(或者断言失败),根本轮不到上线才发现。
TIPS: 让测试数据只允许合法的状态,错误在写的时候就暴露,比线上炸了再查强一万倍。
习惯5、把“期望结果”算清楚,和“实际操作”分开来
场景:测试退款成功后,账户余额对不对。
新手这么写:
def 测试退款():
订单 = 造已支付订单(金额100)
退款(订单)
assert 账户余额 == 100 - 手续费 # 这里直接算,但手续费规则可能变
如果手续费计算规则改了,你得改所有测试里的断言,烦不烦?
高级测试会单独写一个“计算期望”的函数:
def 计算退款后余额(原金额, 费率=0.006):
return 原金额 - 原金额 * 费率
def 测试退款():
订单 = 造已支付订单(金额100)
退款(订单)
期望余额 = 计算退款后余额(100)
assert 账户余额 == 期望余额
这样,如果手续费规则变了,我只改一个函数,所有用到这个计算的测试自动跟着变。
TIPS: 把“算期望”和“执行操作”分开,你的测试更好维护,也更容易单独验证规则对不对。
习惯6、测试失败时,让报错信息出提示
场景:你断言接口返回 200,结果返回了 500。
新手报错就是一句话:
AssertionError: assert 500 == 200
你看到这个信息能干嘛?只能去翻日志,猜是哪个订单、什么参数、为什么失败。半夜出问题,简直想哭。
高级测试会这样写断言——把上下文全带出来:
def 断言退款成功(响应, 订单):
if 响应.status != 200:
raise AssertionError(
f"退款失败!订单号:{订单.id},状态:{订单.状态},"
f"请求参数:{请求数据},返回内容:{响应.text},"
f"追踪ID:{响应.headers.get('X-Request-Id')}"
)
这样一失败,你立刻知道是哪个订单、发了什么、返回了什么,拿着追踪 ID 去日志里一搜,分分钟定位问题。
TIPS: 别让你的断言只输出“对还是错”,要让失败信息自带诊断报告。
习惯7、提交测试代码时,一次只干一件事
场景:你完成了一个退款功能,跑通了,很开心,提交了一个 PR,里面塞了:
- 新增退款测试
- 改动了订单工厂
- 顺手重构了登录测试
- 更新了配置文件
- 加了个风控测试
审查你代码的同事一脸懵:哪些改动是必须的?哪些是顺手改的?万一出问题要回滚,一撤销把登录测试也给撤了,那不乱套?
高级测试会把这些拆成好几个小 PR:
- 第一个 PR:只重构订单工厂(不改任何测试结果)
- 第二个 PR:只新增退款测试(依赖第一个)
- 第三个 PR:只加风控测试(独立)
- 第四个 PR:清理旧配置(独立)
每个 PR 讲一个清楚的故事:“我改了啥,为啥改,对测试有什么影响”。审查的人看得清楚,出问题回滚也安全。
TIPS: 代码不是在你电脑上跑通了就算完,而是要“别人能看懂、能审查、能安全回滚”才算完。
别急着学那些高大上的工具。从今天起,写下一个测试用例时,挑一个习惯用上。半年后再看,你写的用例会稳定、好懂、不坑人。
这,就是变强的样子。想涨薪、想走得更远,最稳妥的办法永远是投资自己的技能。
☑想涨薪、想走得更远,最稳妥的办法永远是投资自己的技能。
☑可如果行业的天花板已经压到头顶,与其在原地内卷,不如借AI的东风换个赛道。
☑AI,正是个低门槛、高成长的方向。
可以戳⬇️⬇️⬇️
公主号【Atstudy技术社区】,内含项目实战等各种资料包
热门跟贴