类型兼容性矩阵测试模式(Schema Evolution)
是什么
类型兼容性矩阵测试是一种数据驱动测试模式,通过穷举类型系统(Type System)中所有可能的新旧类型组合,验证 Schema 演进过程中的向前兼容与向后兼容规则。
核心概念
向前兼容(Forward Compatibility) vs 向后兼容(Backward Compatibility)
旧 Schema → 新 Schema
↓ ↓
写入数据 读取数据
| 概念 | 定义 | 示例 |
|---|---|---|
| 向前兼容 | 用 旧 Schema 写的数据,新 Schema 能读 | BigInt→Int: true(旧 → 新读) |
| 向后兼容 | 用 新 Schema 写的数据,旧 Schema 能读 | Int→BigInt: false(新 → 旧读) |
记忆技巧
- 向前 = 旧数据被新代码读(旧→新,向前演进能读)
- 向后 = 新数据被旧代码读(新→旧,向后退能读)
类型兼容性规则矩阵
@ParameterizedTest(name = "#14/15 类型 {0}→{1} 兼容={2}")
@CsvSource({
"BigInt, Int, true", // 向前兼容:宽度扩大(Int→BigInt)
"Int, BigInt, false", // 不兼容:宽度缩小(BigInt→Int)
"Str, Int, false", // 跨类型变更不兼容
"Str, Text, false", // 跨类型变更不兼容
"Int, Decimal, false", // 跨类型变更不兼容
"Str, Str, true", // 同类型自然兼容
})
void testTypeCompatibility(String from, String to, boolean expected) { ... }测试用例解读
| 测试用例 | 方向 | 兼容性 | 原因 |
|---|---|---|---|
BigInt → Int = true | 旧→新读 | ✅ | Int 存入,BigInt 读取(宽类型能容纳窄类型 → 向上转型) |
Int → BigInt = false | 新→旧读 | ❌ | BigInt 存入,Int 读取(窄类型无法容纳宽类型 → 精度丢失风险) |
Str → Int = false | 任何方向 | ❌ | 类型语义完全不同,无法转换 |
Str → Text = false | 任何方向 | ❌ | 同字符串但不同语义类型,不兼容 |
Int → Decimal = false | 任何方向 | ❌ | 整数→小数,类型系统视为不同 |
Str → Str = true | 同类型 | ✅ | 类型不变,天然兼容 |
典型应用场景
1. Apache Avro Schema Evolution
Avro 是 Hadoop 生态最常用的序列化框架,其 Schema 演进规则就是典型的兼容性矩阵:
- INT → LONG:兼容(宽度扩大)
- LONG → INT:不兼容(宽度缩小)
- STRING → BYTES:兼容
- 添加/删除字段带默认值:兼容
// Avro Schema 兼容性测试
@ParameterizedTest
@CsvSource({
"INT, LONG, true", // 向前兼容
"LONG, INT, false", // 不兼容
"STRING, BYTES, true",
})2. Protocol Buffers(Protobuf)
Protobuf 的字段类型演进规则:
- int32 → int64:兼容(数值范围扩大)
- int64 → int32:兼容但可能截断(运行时无错,数据可能损坏)
- string → bytes:兼容(Wire 格式相同)
3. SQL 数据库 Schema 迁移
-- ❌ 危险迁移:BIGINT → INT(可能导致数据溢出)
ALTER TABLE users ALTER COLUMN id TYPE INT; -- 若存在 > 2^31-1 的值则失败
-- ✅ 安全迁移:INT → BIGINT
ALTER TABLE users ALTER COLUMN id TYPE BIGINT;4. 数据湖格式(Iceberg / Delta Lake / Hive)
列类型变更规则:
- INT → BIGINT:✅ 安全
- FLOAT → DOUBLE:✅ 安全
- DECIMAL(10,2) → DECIMAL(12,2):✅ 精度扩大
- STRING → INT:❌ 不允许
5. API 版本兼容性测试
@ParameterizedTest
@CsvSource({
"2023-01, 2024-01, true", // 旧版本请求 → 新版本 API 处理
"2024-01, 2023-01, false", // 新版本请求 → 旧版本 API 处理
})
void testApiVersionCompatibility(String reqVersion, String apiVersion, boolean compatible) { ... }常见设计原则
类型扩展原则(Type Widening Rule)
byte → short → int → long → float → double
数值从窄到宽始终兼容,反方向不兼容。
兼容性决策树
类型是否相同?
├── 是 → ✅ 兼容
└── 否 → 是否属于同一类型族(数值族/字符串族/时间族)?
├── 是 → 检查宽度:
│ ├── 从窄到宽 → ✅ 向前兼容
│ └── 从宽到窄 → ❌ 不兼容
└── 否 → ❌ 跨族不兼容
相关笔记
- JUnit5-ParameterizedTest与CsvSource — 实现此测试模式的基础注解
- 接口幂等方案设计 — API 版本兼容性与幂等设计常一起出现
- 事务ACID — 数据库 Schema 变更涉及的事务保证