使用Mockito从模拟中抛出检查的异常


173

我正在尝试让我的模拟对象之一在调用特定方法时引发已检查的异常。我正在尝试以下。

@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从模拟对象引发已检查的异常?

Answers:


221

检查Java API中的List
get(int index)方法声明为仅抛出IndexOutOfBoundException扩展的RuntimeException
您试图告诉Mockito抛出一个无效的异常SomeException(),该异常不能由该特定方法调用抛出

进一步澄清。
列表界面不提供用于检查异常从抛出get(int index)的方法,这就是为什么是的Mockito失败。
当您创建嘲笑列表,会的Mockito使用定义列表的.class来创建其模拟。

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

如果您确实想执行此操作,请让Mockito抛出new RuntimeException()或什至更好的抛出a,new ArrayIndexOutOfBoundsException()因为API指定这是唯一要抛出的有效Exception。


虽然我的实际代码并未真正使用List,但是您的答案也适用于该方法调用。我在嘲笑错误的方法。谢谢。
亚瑟·马尔森

2
另外:如果您这样做,则Mocktio不会抱怨抛出一个没有任何可抛出对象的方法,但您也会遇到此异常
dwana 2015年

8
对于Kotliners:Kotlin没有检查过的异常,因此您通常不能(在函数签名中)声明该函数引发异常。但是,您可以使用注释对函数进行Throws注释,以使编译器生成与声明等效Java代码中的throws相同的字节码。有关更多详细信息,请参见[此处](kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-throws/…)。
Javad Sadeqzadeh,

1
Mockito 2.11.0发行以来,便执行了此检查(请参阅2.10.3)
JJD

106

解决方法是使用一种willAnswer()方法。

例如,下面的作品使用(但不抛出,MockitoException但实际上Exception按要求抛出了检查)BDDMockito

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

普通Mockito的等效项将使用该doAnswer方法


9
willAnswer( invocation -> { throw new Exception("abc msg"); }).given(someObj).someMethod(stringArg1);在方法返回时使用void
朱利安·克朗格

9
或使用when(someObj.someMethod(stringArg1))。thenAnswer(invocation-> {throw new Exception(“ abc msg”);});或
Dmitri Algazin

很好的解决方法,谢谢!对于想要(1)无缝地将其用作扩展函数并且(2)能够像willThrow()往常一样传递几个arg的Kotliners ,我写了一个Gist
David Ferrand

2
doAnswernhaarman.mockitokotlin2
HMAC

6

请注意,在一般情况下,的Mockito 允许只要异常在邮件签名中声明抛出checked异常。例如,给定

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只是试图告诉您检查的异常对该方法无效。


5

Kotlin有解决方案:

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

给定来自哪里

导入org.mockito.BDDMockito.given


1

这在Kotlin中对我有用:

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

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


正是我一直在寻找的,可以抛出比其他任何异常Exception
纳伊姆Sarfraz
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.