测试泛型核心是让类型具体化、确保逻辑真实执行、避免误mock关键行为:需用具体类型实例化泛型类或调用泛型方法,覆盖多类型组合与边界情况,验证行为而非运行时类型。

测试泛型类与方法的逻辑,核心在于**让泛型类型具体化、确保逻辑真实执行、避免误 mock 关键行为**。泛型本身在运行时被擦除,但编译期的类型约束和方法逻辑仍可验证——关键不是测“类型”,而是测“行为是否符合泛型语义下的预期”。
明确泛型参数,用具体类型实例化被测对象
泛型类(如 Stack<T>)或泛型方法(如 <T> T findFirst(List<T> list))必须绑定实际类型才能构造实例或调用。测试时不能只写 new Stack()(原始类型),而应指定如 new Stack<String>() 或 new Stack<Integer>()。
- 对泛型类:直接 new 具体类型实例,例如
MyList<Person> list = new MyArrayList<Person>(); - 对泛型方法:调用时显式传入参数或依赖类型推断,如
String s = Utils.<String>getFirst(Arrays.asList("a", "b"));,或让编译器自动推断Utils.getFirst(intList)(intList是List<Integer>) - 若泛型类无默认构造器,可用反射或工厂方法创建;避免使用原始类型,否则失去类型安全,也难验证行为边界
覆盖多组类型组合,验证逻辑一致性
泛型方法/类的逻辑应与类型无关(如排序、转换、容器操作)。需用不同引用类型(String、LocalDateTime、自定义 Order)甚至空值、null 元素等边界情况验证其鲁棒性。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 例如测试
<T> List<T> reverse(List<T> src):分别传入Arrays.asList(1,2,3)、Arrays.asList("x","y")、空列表、null,检查返回值内容、顺序、是否抛出预期异常 - 对泛型类的通用方法(如
add(T item)、get(int i)),重点验证类型安全表现:尝试向Stack<String>add(123) 应编译报错,运行时无需测——这是编译期保障,单元测试不负责验证编译器
针对含默认方法的泛型接口,慎用 spy,只 mock 依赖抽象方法
若泛型接口(如 Converter<D, E>)含默认方法(如 default List<E> convertAll(List<D> ds)),该默认方法是**被测主体**,不可被 mock;它内部调用的抽象方法(如 abstract E convert(D d))才应被模拟。
立即学习“Java免费学习笔记(深入)”;
- 错误做法:对接口类 spy(
spy(Converter.class))——接口无法实例化,会抛异常 - 正确做法:用 Lambda 或匿名类构造轻量实现,再对其 spy:
Converter<UserDTO, User> converter = new Converter<>() { public User convert(UserDTO dto) { return null; } };→Converter<UserDTO, User> spyConv = spy(converter); - 然后 mock 抽象方法:
doReturn(new User()).when(spyConv).convert(any());,再调用spyConv.convertAll(dtoList)验证默认方法逻辑是否正确组装结果
利用断言验证泛型行为,而非类型本身
不要试图用 assertThat(actual.getClass(), is(equalTo(expected.getClass()))) 测类型——运行时已擦除。应聚焦行为:
- 集合类:验证 size()、contains()、get() 返回值是否符合预期(如
stack.pop()是否返回最后 add 的那个String) - 转换类:验证输入
List<String>后,输出List<Integer>的每个元素是否为对应字符串长度 - 使用
assertNotNull()、assertEquals()、assertTrue(list instanceof List)(仅判断是否为某接口,非具体参数化类型)等标准断言

















