我试图让我的一个模拟对象抛出一个checked Exception当一个特定的方法被调用。我正在尝试以下方法。

@Test(expectedExceptions = SomeException.class)
public void throwCheckedException() {
    List<String> list = mock(List.class);
    when(list.get(0)).thenThrow(new SomeException());
    String test = list.get(0);
}

public class SomeException extends Exception {
}

但是,这会产生以下错误。

org.testng.TestException: 
Expected exception com.testing.MockitoCheckedExceptions$SomeException but got org.mockito.exceptions.base.MockitoException: 
Checked exception is invalid for this method!
Invalid: com.testing.MockitoCheckedExceptions$SomeException

看看Mockito文档,他们只使用RuntimeException,是不是不可能从Mockito的模拟对象抛出受控异常?


当前回答

注意,通常情况下,Mockito允许抛出检查过的异常,只要异常在消息签名中声明了。例如,给定

class BarException extends Exception {
  // this is a checked exception
}

interface Foo {
  Bar frob() throws BarException
}

这样写是合法的:

Foo foo = mock(Foo.class);
when(foo.frob()).thenThrow(BarException.class)

然而,如果你抛出一个未在方法签名中声明的受控异常,例如。

class QuxException extends Exception {
  // a different checked exception
}

Foo foo = mock(Foo.class);
when(foo.frob()).thenThrow(QuxException.class)

Mockito将在运行时失败,并给出一些误导性的通用消息:

Checked exception is invalid for this method!
Invalid: QuxException

这可能会导致您认为受控异常通常是不受支持的,但实际上Mockito只是试图告诉您该受控异常对于该方法无效。

其他回答

检查List的Java API。 get(int index)方法被声明为只抛出IndexOutOfBoundException,它扩展了RuntimeException。 您试图告诉Mockito抛出一个异常SomeException(),该异常不适合由该特定方法调用抛出。

为了进一步澄清。 List接口没有提供从get(int index)方法抛出的受控异常,这就是Mockito失败的原因。 当您创建模拟列表时,Mockito将使用List.class的定义来创建它的模拟。

使用when(list.get(0))指定的行为。thenThrow(new SomeException())不匹配List API中的方法签名,因为get(int index)方法不抛出SomeException(),因此Mockito失败。

如果你真的想这样做,那么让Mockito抛出一个新的RuntimeException(),或者更好的是抛出一个新的ArrayIndexOutOfBoundsException(),因为API指定这是唯一要抛出的有效异常。

一种变通方法是使用willAnswer()方法。

例如,使用BDDMockito进行以下工作(并且不会抛出MockitoException,但实际上会抛出一个检查异常):

given(someObj.someMethod(stringArg1)).willAnswer( invocation -> { throw new Exception("abc msg"); });

普通Mockito的等价物将使用doAnswer方法

Kotlin有一个解决方案:

given(myObject.myCall()).willAnswer {
    throw IOException("Ooops")
}

given从何而来

进口org.mockito.BDDMockito.given

注意,通常情况下,Mockito允许抛出检查过的异常,只要异常在消息签名中声明了。例如,给定

class BarException extends Exception {
  // this is a checked exception
}

interface Foo {
  Bar frob() throws BarException
}

这样写是合法的:

Foo foo = mock(Foo.class);
when(foo.frob()).thenThrow(BarException.class)

然而,如果你抛出一个未在方法签名中声明的受控异常,例如。

class QuxException extends Exception {
  // a different checked exception
}

Foo foo = mock(Foo.class);
when(foo.frob()).thenThrow(QuxException.class)

Mockito将在运行时失败,并给出一些误导性的通用消息:

Checked exception is invalid for this method!
Invalid: QuxException

这可能会导致您认为受控异常通常是不受支持的,但实际上Mockito只是试图告诉您该受控异常对于该方法无效。

这适用于我在Kotlin:

when(list.get(0)).thenThrow(new ArrayIndexOutOfBoundsException());

注意:抛出除exception()以外的任何定义异常