抛出与Mockito模拟的例外情况

Art*_*son 140 java mocking mockito

我正在尝试让我的一个模拟对象在调用特定方法时抛出一个已检查的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 {
}
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

看看Mockito文档,他们只使用RuntimeException,是否不可能使用Mockito从模拟对象中抛出已检查的异常?

Joh*_*man 193

检查Java API for List.声明get(int)方法只抛出扩展RuntimeException的IndexOutOfBoundException.您试图告诉Mockito抛出一个异常,该异常无法被该特定方法调用抛出.

进一步澄清.List接口不提供从get()方法抛出的已检查异常,这就是Mockito失败的原因.当您创建模拟List时,Mockito使用List.class的定义来创建其模拟.您使用它指定的行为与when(list.get(0)).thenThrow(new SomeException())List.class中的方法签名不匹配,因此Mockito失败.如果你真的想这样做,那么让Mockito抛出一个new RuntimeException()甚至更好的抛出一个,new ArrayIndexOutOfBoundsException()因为API指定这是唯一有效的异常抛出.

  • 对于Kotliners:Kotlin没有检查异常,所以你通常不能声明(在函数签名中)函数抛出异常.但是,您可以使用`Throws`批注对函数进行批注,以使编译器生成与在等效Java代码中声明抛出相同的字节码.有关详细信息,请参阅[此处](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-throws/index.html). (4认同)
  • 自 [Mockito 2.11.0(参见 2.10.3)](https://github.com/mockito/mockito/blob/release/2.x/doc/release-notes/official.md) 发布以来强制执行此检查#2110-2017-10-14-发布到 jcentermaven-central)。 (3认同)
  • 额外:如果你做一个没有任何抛出物的方法,Mocktio不会抱怨,但你也会得到这个例外 (2认同)

Dee*_*pak 79

解决方法是使用willAnswer()方法.

例如,以下工作(并且不会抛出MockitoException但实际上Exception在此处根据需要抛出一个检查)使用BDDMockito:

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

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

  • 或者使用`willAnswer(invocation - > {throw new Exception("abc msg");}).given(someObj).someMethod(stringArg1);`当方法返回`void`时. (8认同)
  • 或使用when(someObj.someMethod(stringArg1))。thenAnswer(invocation-&gt; {throw new Exception(“ abc msg”);});或使用 (7认同)

Kev*_*OUX 13

Kotlin 有解决方案:

given(myObject.myCall()).willAnswer {
    throw IOException("Ooops")
}
Run Code Online (Sandbox Code Playgroud)

给定的来源

导入 org.mockito.BDDMockito.given

  • 这也适用于 Java `.thenAnswer((t) -&gt; { throw new IOException(); });` (10认同)

Dav*_*les 12

请注意,一般而言,Mockito确实允许抛出已检查的异常,只要该异常在消息签名中声明即可。例如,给定

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

interface Foo {
  Bar frob() throws BarException
}
Run Code Online (Sandbox Code Playgroud)

写是合法的:

Foo foo = mock(Foo.class);
when(foo.frob()).thenThrow(BarException.class)
Run Code Online (Sandbox Code Playgroud)

但是,如果您抛出未在方法签名中声明的已检查异常,例如

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

Foo foo = mock(Foo.class);
when(foo.frob()).thenThrow(QuxException.class)
Run Code Online (Sandbox Code Playgroud)

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

Checked exception is invalid for this method!
Invalid: QuxException
Run Code Online (Sandbox Code Playgroud)

这可能会让您认为检查异常通常不受支持,但实际上 Mockito 只是想告诉您检查异常对于此方法无效。


Alo*_*pta 7

这在 Kotlin 中对我有用:

when(list.get(0)).thenThrow(new ArrayIndexOutOfBoundsException());
Run Code Online (Sandbox Code Playgroud)

注意:抛出 Exception() 之外的任何定义的异常

  • 这根本没有回答问题!`ArrayIndexOutOfBoundsException` 是一种未经检查的异常,而不是经过检查的异常。 (2认同)