Java 如何测试泛化API的类型安全性?
例如,您可以使用JUnit来测试库的功能,但是如何测试泛型和通配符的类型安全性呢 只有针对编译代码的测试才是“快乐路径”测试;您是否应该针对非类型安全的用法测试您的API,并确认这些代码不可编译Java 如何测试泛化API的类型安全性?,java,api,generics,testing,type-safety,Java,Api,Generics,Testing,Type Safety,例如,您可以使用JUnit来测试库的功能,但是如何测试泛型和通配符的类型安全性呢 只有针对编译代码的测试才是“快乐路径”测试;您是否应该针对非类型安全的用法测试您的API,并确认这些代码不可编译 // how do you write and verify these kinds of "tests"? List<Number> numbers = new ArrayList<Number>(); List<Object> object
// how do you write and verify these kinds of "tests"?
List<Number> numbers = new ArrayList<Number>();
List<Object> objects = new ArrayList<Object>();
objects.addAll(numbers); // expect: this compiles
numbers.addAll(objects); // expect: this does not compile
//如何编写和验证这些类型的“测试”?
列表编号=新的ArrayList();
列表对象=新的ArrayList();
objects.addAll(数字);//expect:此编译
number.addAll(对象);//expect:这不会编译
那么,如何验证泛型API在编译时是否引发了正确的错误呢?您是否只是构建了一个非编译代码的套件来测试您的库,并将编译错误视为测试成功,反之亦然?(当然,您必须确认错误与泛型相关)
是否有框架可以促进此类测试?听起来您正在尝试测试Java编译器,以确保如果您分配了错误的类型,它将引发正确的编译错误(而不是测试您自己的api)
如果是这样的话,为什么不担心编译器在为字符串字段分配整数、调用尚未初始化的对象上的方法以及编译器在编译代码时应该检查的其他数百万项时不会失败呢 我想你的问题并不局限于泛型。我们可以对非泛型代码提出同样的问题。如果你描述的工具存在,我会害怕的。有很多人非常乐意测试他们的能手和二传手(并尝试在其他人身上实施)。现在,他们更乐于编写新的测试,以确保不会编译对其私有字段的访问!哦,人性
但我猜泛型要复杂得多,所以你的问题没有意义。对于大多数程序员来说,如果他们能最终编译他们该死的泛型代码,他们会很高兴的。如果一段泛型代码没有编译(这是开发过程中的常态),他们真的不知道该怪谁。因为这不是传统意义上的测试(也就是说,你不能“运行”测试),我认为这样的工具不存在,我可以建议如下:
您可以为该功能制作一个易于使用的包装器,并为任何有需求的人提供它。也许您可以在单元测试中使用Collections.checkedList()。下面的示例将编译,但会引发ClassCassException。以下示例摘自@Simon G
List<String> stringList = new ArrayList<String>();
List<Number> numberList = Collections.checkedList(new ArrayList<Number>(), Number.class);
stringList.add("a string");
List list = stringList;
numberList.addAll(list);
System.out.println("Number list is " + numberList);
List-stringList=new-ArrayList();
List numberList=Collections.checkedList(新的ArrayList(),Number.class);
添加(“字符串”);
列表=字符串列表;
numberList.addAll(列表);
System.out.println(“数字列表为”+numberList);
测试编译失败听起来像是找错了方向,然后用螺丝刀再次剥去树皮。为正确的工作使用正确的工具
我认为您需要一个或多个:
- 代码审查(可能由JRT之类的代码审查工具支持)
- 静态分析工具(FindBugs/CheckStyle)
- 切换语言到C++,支持实现(也可能需要将宇宙切换到其中存在这样一个实现的一个)。
- 不要使用任何
@SuppressWarnings
- 确保编译时没有警告(或错误)
ClassCastException
),除非它源于用户级的强制转换操作(如果使用泛型编程,则很少再需要此类强制转换)。唯一的后门是使用原始类型与Java 5之前的代码进行互操作,但是对于这些情况,编译器将发出警告,例如臭名昭著的“unchecked cast”警告,以指示类型安全性可能受到损害。但是,如果没有此类警告,Java将保证您的类型安全
因此,除非您是编译器编写者(或者您不信任编译器),否则想要测试“类型安全性”似乎很奇怪。在您给出的代码示例中,如果您是
ArrayList
的实现者,您应该只注意为addAll
提供最灵活的类型签名,以允许您编写功能正确的实现。例如,可以将参数键入“代码>集合< /COD>”,也可以作为“代码>集合< <代码> >或代码>集合> p>,在C++中,他们试图用概念来实现这一点,但从标准中启动。
使用Eclipse,当Java中的某些东西无法编译时,我可以很快地恢复,并且错误消息非常直接。例如,如果您希望一个类型有一个特定的方法调用,但它没有,那么您的编译器会告诉您需要知道什么。与类型不匹配的情况相同
幸运的是,将编译时概念构建到java:p中需要直观地验证预期不可编译代码的编译是否工作似乎不符合单元测试的精神,单元测试应该能够通过单击按钮或快速键盘快捷键来运行。你也许可以