Python / 装饰器
1. 装饰器在自动化测试里有什么实际价值?
我会把装饰器理解成给函数统一加能力的方式。在自动化里它最大的价值不是语法炫技,而是把重复逻辑从 case 里抽出去。比如重试、日志、耗时统计、鉴权注入,这些能力如果散落在每个用例里,后期维护成本会非常高。
我在项目里最常见的用法,就是给接口 case 增加重试和日志。因为测试环境偶尔会有瞬时波动,比如网络超时、连接中断,这类问题不一定是业务缺陷,但如果每个 case 都自己处理,代码会很乱。用装饰器后,所有策略都统一了,case 只保留业务表达,代码可读性和一致性都会高很多。
不过我会强调两个边界。第一,装饰器不能吞异常,真正失败时必须把原始异常抛出来;第二,装饰器要保留原函数名称和注释,否则测试报告可读性会变差。所以装饰器的核心不是能不能写,而是能不能统一治理并且不破坏可维护性。
关键词:统一能力、减少重复、保留异常、保证报告可读性。
Python / 带参数装饰器
2. 带参数装饰器你怎么理解?
带参数装饰器本质上是把策略配置化。普通装饰器只能统一加功能,但带参数装饰器可以让这个功能在不同场景下有不同表现。比如同样是重试,支付接口可能只允许重试一次,查询接口可能可以重试三次;网络超时可以重试,业务校验失败就不能重试。
我在项目里会把重试次数、间隔、异常白名单都做成参数,这样不同模块复用同一套实现,而不是每个模块复制一份逻辑。这样做的好处是策略集中、修改成本低,而且 smoke 和 nightly 这种不同执行场景也可以挂不同参数。
如果面试官追问实现原理,我会说它通常是三层函数:外层收参数,中层接原函数,内层执行业务逻辑。但我不会把重点放在语法细节,而是强调为什么要这样设计,因为工程实践比写三层 def 更重要。
关键词:策略配置化、异常白名单、不同执行场景。
Python / 闭包
3. 闭包在测试 case 开发里的常见坑是什么?
闭包最常见的坑是循环变量绑定问题。很多人动态生成 case 时,会在循环里定义 lambda 或内部函数,结果最后所有生成出来的 case 都拿到了同一个变量值。表面上像生成了很多 case,实际上测的是同一组数据,这会形成假覆盖。
我遇到过类似问题:批量生成接口回归 case 时,报告里名字看起来都不一样,但执行的数据完全相同,最后漏掉了一批边界场景。这个问题最麻烦的地方在于它不一定直接报错,而是 quietly 把覆盖质量做坏了。
所以我的做法是,动态生成 case 时一定把当前变量显式绑定住,或者用参数化替代手写闭包生成。另外我会要求 case 名称里带关键参数,这样从报告层就能看出生成逻辑有没有问题。
关键词:循环变量、假覆盖、报告可解释性。
Python / 上下文管理器
4. 上下文管理器在自动化测试里能解决什么问题?
我会把上下文管理器理解成资源生命周期控制工具。在自动化里,很多资源不是简单创建完就结束,比如临时用户、数据库连接、临时文件、浏览器上下文、Mock 会话,这些都需要在测试完成后清理掉。如果只靠 try finally 手工写,代码容易散,也容易漏。
上下文管理器的价值就在于,不管 case 成功还是失败,退出时都能保证清理动作执行。这个能力对长期稳定运行非常重要,因为自动化最怕的不是一次失败,而是环境越跑越脏,最后所有 case 开始互相影响。
所以我在项目里会把临时资源都封成上下文管理器,比如创建一个临时测试用户,用完自动删除。面试时我会强调一点:上下文管理器不是为了写得优雅,而是为了把资源释放变成强约束,而不是靠开发者记忆。
关键词:资源生命周期、强制清理、环境稳定。
pytest / fixture
5. fixture 工厂化设计你会怎么回答?
我一般不会把 fixture 做成固定返回一个对象,而是更倾向于做成返回一个工厂函数。因为测试场景往往很多变,比如用户有 admin、guest、frozen 三种状态,订单又有未支付、已支付、已退款多种状态。如果每种状态都写一个独立 fixture,很快就会膨胀,而且复用性很差。
工厂化设计的思路是,让 fixture 提供能力,而不是提供写死的数据。比如 user_factory 可以根据参数创建不同角色的用户,order_factory 可以创建不同状态的订单。这样一个 fixture 能覆盖很多场景,用例只需要表达自己关心的业务条件。
但我会特别控制 fixture 的作用域。默认优先函数级,因为隔离性最好。只有当初始化成本很高,而且数据是只读或不会污染时,我才会考虑 session 级。对我来说,fixture 设计的核心不是省几行代码,而是数据隔离、复用性和长期稳定性三者的平衡。
关键词:能力型 fixture、工厂函数、作用域控制。
pytest / 参数化
6. 参数化测试怎么做才不是机械堆数据?
我认为参数化测试最大的误区,就是把它当成批量塞数据的工具。真正有价值的参数化,一定是建立在测试设计基础上的。也就是说,先有等价类、边界值、异常流和组合流分析,再有参数矩阵,而不是反过来。
我在设计参数化 case 时,会先问自己两个问题:第一,这组参数在验证什么风险;第二,如果它失败了,我能不能快速知道是哪类问题。如果这两个问题答不上来,那参数化就只是数量堆砌,不是真正的覆盖。
工程上,我会把参数数据和断言规则分离,避免后期改一个参数就拖垮整组断言。对于关键路径,我还会给参数集打标签,支持 smoke 和 regression 分层执行。所以我理解的参数化不是批量执行,而是结构化覆盖。
关键词:测试设计先行、风险映射、结构化覆盖。
Python / typing
7. typing 在测试代码里有必要吗?
我认为有必要,但前提是用得克制。测试代码虽然不像生产代码那样稳定,但它一样会演进、会协作、会被多人维护。加上类型标注后,函数输入输出会更清晰,IDE 补全更好,重构时也更安全。
我在实际使用时,最常给数据构造函数、业务封装层和工具函数加类型标注。比如 payload builder、响应解析函数、fixture 返回值,这些地方一旦标清楚,后续阅读和修改成本会明显下降。
不过我不会为了全量 typing 而牺牲开发效率。我的原则是,公共层和稳定层优先标,临时脚本和一次性探索代码不强求。这样既能得到工程收益,又不会把团队拖进过度形式化。
关键词:可读性、重构安全、克制使用。
Python / 并发
8. 测试开发里怎么选择多线程、多进程和异步?
我通常先看任务类型,再决定并发模型。I/O 密集型任务,比如批量接口调用、日志采集、文件上传下载,更适合线程或异步;CPU 密集型任务,比如大规模数据计算、复杂加解密,更适合多进程。
在自动化里,大多数任务其实更接近 I/O 密集,所以我更常用线程池或异步,因为实现成本相对低,也更容易和现有接口封装集成。
不过我会强调一点,并发的目的不只是提速,还包括验证竞态和一致性问题。比如并发下单、并发扣库存、重复提交幂等,这些场景如果只关注跑得快,就会漏掉真正关键的风险。所以我在面试里会把并发回答成“性能 + 正确性”两个维度,而不是只谈技术选型。
关键词:先看任务类型、性能 + 正确性。