4. 兼容性测试策略

兼容性测试,到底测什么?

说白了,就这四样:前向兼容、后向兼容、API兼容性、行为兼容性。光测一个不够,全得覆盖到。我见过太多团队只盯着「新功能能用」,结果老业务崩了,用户骂街。

核心原则:后向兼容是底线,API兼容是契约,行为兼容是信誉,前向兼容是远见。
兼容性测试策略框架图 兼容性测试策略知识体系 兼容性测试策略 前向兼容 后向兼容 API兼容性 行为兼容性 说明: 前向兼容面向未来SDK版本;后向兼容守住老用户;API兼容确保接口不破; 行为兼容维护用户体验一致性。四者缺一不可。

4.1 前向兼容 vs 后向兼容

这两个概念,刚入行的兄弟容易搞混。我给你捋一捋:

维度前向兼容后向兼容
定义 新版本SDK写的代码,能在旧版本SDK上运行 旧版本SDK写的代码,能在新版本SDK上正常运行
关注点 新特性降级、API版本感知 废弃API、数据结构变更
测试方向 旧环境跑新代码 新环境跑旧代码
典型问题 调用不存在的API、格式不兼容 返回字段缺失、行为突变

我记得刚入行那会儿,做支付SDK。新版本加了个加密字段,结果老版本根本没这个字段。我没有做降级处理,直接让老SDK的APP调用新接口,崩了。你说冤不冤?前向兼容,就是要你考虑「用户不升级」的情况。

小技巧:写SDK时,新API加标记,比如 @since(2.0.0)。运行时检查版本号,低于某个版本就走降级逻辑。

后向兼容呢,更常见。你升级了SDK,老用户不更新你的库,但他调你的API。你不能改响应结构,不能删字段。我有个同事,新版本把返回的 status 字段名改成了 state,结果线上很多老代码直接用 response.status ——全挂了。你说这算不算低级错误?

4.2 API兼容性

API兼容性,是SDK和调用方之间的契约。

一旦对外发布,接口签名就是承诺。举个例子:

// v1.0.0 - 原版
public User getUser(int id)

// v2.0.0 - 改了参数类型,不兼容
public User getUser(String id)

// 调用方按int传参,编译都过不了,更别说运行了

API兼容性需要关注以下几个维度:

  • 方法签名不变:方法名、参数类型、返回类型不能变。
  • 异常类型不变:新增异常可以,但不能删除已有异常。
  • 字段不能删:JSON响应里,之前有 errorMsg,新版本不能去掉。
  • 枚举值不能砍:状态码、枚举常量只能增不能减。
警告:签名兼容 ≠ 行为兼容。接口没变,但内部逻辑变了,这才是隐藏最深的坑。我亲历过一次,接口返回格式没变,但排序规则改了,前端没发现,上线后数据对不上,排查了一整天。

怎么测API兼容性?我的习惯是这样的:

  1. 把旧版本SDK和调用方代码打包成测试项目。
  2. 用新版本SDK替换旧SDK的jar/aar包。
  3. 不修改调用方代码,直接运行已有测试用例。
  4. 如果编译通过、测试全绿,API兼容性就算过了。

4.3 行为兼容性

行为兼容性,是最容易被忽略的。

你想想看,API没变,返回值格式没变,但——

  • 同一个操作,以前返回空字符串,现在返回null
  • 以前是同步的,现在改成了异步
  • 以前异常是 IOException,现在变成了 RuntimeException

这些都属于行为不兼容。你说接口没坏吧?调用方逻辑完全可能炸。

有一次我们升级了底层图像算法,接口还是 Image process(Image input),返回的也是 Image。但新版本对某些角度的图片处理耗时从50ms飙到了500ms。调用方没设超时,结果整个APP卡死。你说这是API问题吗?不是。是行为问题。

行为兼容性测试,要盯的是:

检查点说明
返回值语义null vs 空对象、顺序是否一致、默认值是否不变
异常语义异常类型、错误码、异常消息格式
性能特征响应时间是否退化、内存消耗是否剧增
副作用写文件、发网络请求、改全局状态等行为是否新增或减少
并发行为锁粒度变化、线程模型变化

测行为兼容性,光靠单元测试不够。我建议你拿老版本的测试用例,直接在线上切换前后对比看差异。或者用diff工具比较两个版本的完整调用日志。我曾经手工跑了一百多个回归用例,就为了确认同一个输入,输出是否完全一致。

我这里有个检查清单:每次回归测试,把这四点过一遍——前向兼容、后向兼容、API兼容、行为兼容。少一个,线上事故风险就高一分。
个人建议:如果你的SDK有百万以上用户量,行为兼容性必须加自动化回归流程。光靠人肉测,迟早出问题。