Java泛型在运行时被擦除,List<String>和List<Integer>均变为原始类型List,仅编译期保留类型检查;测试应聚焦实际对象类型、内容与行为,而非泛型声明。

测试带有泛型的复杂返回结果,关键不在“泛型”本身,而在于**运行时类型已擦除**这一事实。JUnit 测试的是方法执行后的实际对象,不是编译期的泛型声明。所以重点是:确认返回对象的**真实类型、结构、内容和行为是否符合预期**。
看清泛型擦除后的实际返回对象
Java 泛型在编译后会被擦除,比如 List<User> 运行时就是 List,里面的元素类型信息不保留。因此测试时不能依赖泛型声明做断言,而要关注:
- 方法是否真的返回了非 null 的集合或对象实例
- 集合中每个元素是否是预期的具体类型(如
User),可通过instanceof或getClass()验证 - 对象字段值、状态、业务逻辑是否正确(比如
user.getName()是否等于 "张三")
用 assertEquals 验证内容,不用 assertSame 验证泛型类型
assertEquals 依赖对象的 equals() 方法,适合验证数据一致性;assertSame 比较内存地址,对泛型集合无意义。例如:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- ✅ 正确:验证返回的
List<User>是否包含指定姓名的用户(需确保User正确定义了equals和hashCode) - ❌ 错误:试图用
assertEquals(new ArrayList<String>(), result)去比对泛型类型——类型擦除后两者都是ArrayList,但内容不同仍会失败,且语义不清
对空值、异常和边界情况单独覆盖
泛型方法常因输入非法或条件不满足而返回 null 或抛异常,这些场景必须显式测试:
立即学习“Java免费学习笔记(深入)”;
- 用
assertNull()检查空返回(如查询不存在的 ID 导致返回Optional<Product>为空) - 用
@Test(expected = IllegalArgumentException.class)或assertThrows()验证参数不合法时是否抛出预期异常 - 测试空集合、单元素集合、含 null 元素等边界输入,确认泛型方法处理逻辑健壮
需要反射获取泛型信息?通常没必要
除非你在写通用框架(如 JSON 反序列化工具),否则单元测试中极少需要通过反射读取泛型实际类型参数。因为:
- 业务代码只关心“它是不是 User”,而不是“声明里写了 <User>”
- 反射读取
ParameterizedType复杂、易错,且掩盖了设计问题(比如该用更明确的返回类型或封装类) - 真正该测的是行为:调用后得到的对象能不能安全调用
getName()?会不会ClassCastException?

















