我们在工作时使用JUnit 3,没有ExpectedException
注释。我想在我们的代码中添加一个实用程序来包装它:
try {
someCode();
fail("some error message");
} catch (SomeSpecificExceptionType ex) {
}
所以我尝试了这个:
public static class ExpectedExceptionUtility {
public static <T extends Exception> void checkForExpectedException(String message, ExpectedExceptionBlock<T> block) {
try {
block.exceptionThrowingCode();
fail(message);
} catch (T ex) {
}
}
}
但是,我认为Java不能在catch块中使用泛型异常类型。
我如何做这样的事情,解决Java限制?
有没有办法检查ex
变量的类型为T
?
答案 0 :(得分:28)
您可以传递Class对象并以编程方式检查它。
public static <T extends Exception> void checkForException(String message,
Class<T> exceptionType, ExpectedExceptionBlock<T> block) {
try {
block.exceptionThrowingCode();
} catch (Exception ex) {
if ( exceptionType.isInstance(ex) ) {
return;
} else {
throw ex; //optional?
}
}
fail(message);
}
//...
checkForException("Expected an NPE", NullPointerException.class, //...
我不确定你是否想要重新抛出;重新抛出同样会失败/错误测试但在语义上我不会,因为它基本上意味着“我们没有得到我们预期的异常”,因此这代表编程错误,而不是测试环境错误。
答案 1 :(得分:4)
我理解尝试简化异常测试习惯的冲动,但严重的是:不要。你想出的每一个可能的选择都是比疾病更糟糕的治疗方法。 特别是 JUnit 4的@ExpectedException废话!这是一个过于聪明的框架式解决方案,需要每个人都能学习它是如何工作的,而不是普通的Java代码。更糟糕的是,它无法仅包装您希望抛出异常的测试部分,因此如果早期的安装步骤抛出相同的异常,即使您的代码被破坏,您的测试也会通过。
我可以在这里写一篇很长的诽谤(我很抱歉没有足够的时间),因为我们在谷歌的Java工程师中对这个问题进行了长时间的讨论,并且达成的共识是这些疯狂的解决方案是值得的。习惯尝试/捕捉,它真的没那么糟糕。
答案 2 :(得分:1)
泛型不是类型。它们不是模板。它们是Java中的编译时类型检查。异常块捕获类型。您可以捕获(例外e)甚至捕获(Throwable e)然后根据需要进行投射。
答案 3 :(得分:0)
好吧,如果它不是预期的异常,你可以捕获异常并重新抛出。虽然良好的编码实践通常要求代码的成功路径不应该由异常定义,因此您可能需要重新考虑您的设计。
答案 4 :(得分:0)
您还可以使用支持实时模板的IDE(如IntellJ IDEA for instance)并指定一个快捷方式,如ee -> [tab]
,为您插入try / catch / ignore,并让您输入正确的。
like this http://img80.imageshack.us/img80/433/capturadepantalla201006j.png
like this http://img641.imageshack.us/img641/6733/capturadepantalla201006w.png
答案 5 :(得分:0)
答案 6 :(得分:0)
@FunctionalInterface
public interface ThrowingConsumer<T, E extends Exception> {
void accept(T t) throws E;
}
public static <T, E extends Exception> Consumer<T> errConsumerWrapper(ThrowingConsumer<T, E> throwingConsumer,
Class<E> exceptionClass,
Consumer<E> exceptionConsumer) {
return i -> {
try {
throwingConsumer.accept(i);
} catch (Exception ex) {
try {
exceptionConsumer.accept(exceptionClass.cast(ex));
} catch (ClassCastException ccEx) {
throw new RuntimeException(ex);
}
}
};
}
用法示例
Stream.of(“ a”)。forEach(errConsumerWrapper(i-> Integer.parseInt(i), NumberFormatException.class, Throwable :: printStackTrace));