我有这样的方法:
public void getSomething(){
...
}
我想扔一个Exception
里面getSomething()
。编译器不允许我这样做,因为我的方法不允许Exception
被扔在那里。但是我需要Exception
为我的测试抛出一个子类(我不能抛出 Unchecked Exception
)。这显然是一个 hack,但我需要它来进行测试。我尝试了 EasyMock,但它也不允许我这样做。任何想法如何做到这一点?
谢谢,肖恩阮
我有这样的方法:
public void getSomething(){
...
}
我想扔一个Exception
里面getSomething()
。编译器不允许我这样做,因为我的方法不允许Exception
被扔在那里。但是我需要Exception
为我的测试抛出一个子类(我不能抛出 Unchecked Exception
)。这显然是一个 hack,但我需要它来进行测试。我尝试了 EasyMock,但它也不允许我这样做。任何想法如何做到这一点?
谢谢,肖恩阮
方法一:
Alexey Ragozin 的这篇文章描述了如何使用泛型技巧来引发未声明的检查异常。从那个帖子:
public class AnyThrow {
public static void throwUnchecked(Throwable e) {
AnyThrow.<RuntimeException>throwAny(e);
}
@SuppressWarnings("unchecked")
private static <E extends Throwable> void throwAny(Throwable e) throws E {
throw (E)e;
}
}
该技巧依赖于throwUnchecked
对编译器的“谎言”,即类型E
是RuntimeException
调用throwAny
. 由于throwAny
被声明为throws E
,编译器认为特定的调用可以只是 throw RuntimeException
。当然,这个技巧是通过throwAny
任意声明E
和盲目地转换为它来实现的,允许调用者决定它的参数被转换成什么 - 理智编码时的糟糕设计。在运行时,E
被擦除并且没有任何意义。
正如你所指出的,做这样的事情是一个巨大的 hack,你应该很好地记录它的使用。
方法二:
您也可以sun.misc.Unsafe
为此使用。首先,您必须实现一个使用反射返回该类实例的方法:
private static Unsafe getUnsafe() {
try {
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
return (Unsafe)theUnsafeField.get(null);
}
catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
这是必要的,因为调用Unsafe.getUnsafe()
通常会抛出SecurityException
. 一旦你有了实例,Unsafe
你就可以使用它的可怕功能:
Unsafe unsafe = getUnsafe();
unsafe.throwException(new Exception());
归功于帖子https://stackoverflow.com/questions/5574241/interesting-uses-of-sun-misc-unsafe上的这个答案。我想我会为了完整性而提到这一点,但最好只使用上面的技巧而不是允许进入你的代码。Unsafe
方法三:
在有关 using 的链接答案的评论中Unsafe
,@bestsss 指出了一个使用已弃用方法的更简单的技巧Thread.stop(Throwable)
:
Thread.currentThread().stop(new Exception());
在这种情况下,您将使用@SuppressWarnings("deprecation")
并再次非常激烈地记录。同样,我更喜欢第一个技巧,因为它的(相对)清洁度。
Java有两种异常,checked和unchecked。您必须声明已检查的异常,但不必声明未检查的异常。
RuntimeException
是基本的未经检查的异常,因此您可以在不声明的情况下抛出它。
public void getSomething(){
throw new RuntimeException("I don't have to be declared in the method header!");
}
附带说明一下,您可能不想抛出原始 RuntimeException,而是将其子类化为更符合您需求的东西。RuntimeException 的任何子类也将被取消选中。
我不知道你想做什么。您可以在方法中抛出未经检查的异常,然后使用 JUnit 进行测试,如下面的示例所示。
public void getSomething() {
throw new RuntimeException();
}
JUnit 4 测试示例:
@Test
public void testGetSomething() {
try {
getSomething();
fail("Expecting RuntimeException!");
} catch (Exception e) {
Logger.getLogger("test").info("Exception was caught: " + e.getClass());
}
}