【问题标题】:Cannot throw an exception using Mockito无法使用 Mockito 引发异常
【发布时间】:2014-11-20 05:24:39
【问题描述】:

当方法运行时,我想抛出异常(在测试时)。 我可以做几件事:

  1. stub(mock.someMethod("some arg")).toThrow(new RuntimeException());
  2. when(mock.someMethod("some arg")).thenThrow(new RuntimeException())
  3. 投掷.....

通常我会创建一个 spy 对象来调用 spy 方法。使用存根我可以抛出异常。此异常始终在日志中进行监控。更重要的是测试不会崩溃,因为抛出异常的方法可以捕获它并返回特定的值。但是,在下面的代码中没有抛出异常(日志中没有任何内容被监控 && 返回值为真但应该为假)。

问题:在这种情况下不会抛出异常:

    DeviceInfoHolder deviceInfoHolder = new DeviceInfoHolder();

    /*Create Dummy*/

    DeviceInfoHolder mockDeviceInfoHolder = mock (DeviceInfoHolder.class);

    DeviceInfoHolderPopulator deviceInfoHolderPopulator  = new DeviceInfoHolderPopulator(); 

    /*Set Dummy */
    deviceInfoHolderPopulator.setDeviceInfoHolder(mockDeviceInfoHolder);

    /*Create spy */
    DeviceInfoHolderPopulator spyDeviceInfoHolderPopulator = spy(deviceInfoHolderPopulator);

    /*Just exception*/
    IllegalArgumentException toThrow = new IllegalArgumentException();

    /*Stubbing here*/
    stub(spyDeviceInfoHolderPopulator.populateDeviceInfoHolder()).toThrow(toThrow);

    /*!!!!!!Should be thrown an exception but it is not!!!!!!*/
    boolean returned = spyDeviceInfoHolderPopulator.populateDeviceInfoHolder();
    Log.v(tag,"Returned : "+returned);

【问题讨论】:

  • 检查你的方法不是最终的。最终方法不能被存根。
  • 您想通过此日志记录实现什么目标?如果您的测试方法抛出异常,只需将其冒泡,测试框架将负责记录
  • 如果在方法内部抛出异常,它将返回false。
  • 我想测试方法中什么时候会抛出异常的返回。记录只是为了观察

标签: java android testing mockito stubs


【解决方案1】:

创建新答案,因为 spyDeviceInfoHolderPopulator.populateDeviceInfoHolder();是你的测试方法。

单元测试的基本规则之一是你不应该存根测试方法,因为你想测试它的行为。您可能希望使用 Mockito 对测试类的伪造依赖项的方法进行存根。

因此,在这种情况下,您可能想要删除间谍,调用您的测试方法,作为测试的最后阶段(目前缺少),您应该验证测试方法中的逻辑是否正确。

编辑:

在最后一次评论之后,我终于清楚你正在测试什么逻辑。 假设您的测试对象依赖于某些 XmlReader。还想象一下,这个阅读器有一个名为“readXml()”的方法,并在您的测试逻辑中用于从 XML 中读取。我的测试看起来像这样:

XmlReader xmlReader = mock (XmlReader.class);
mock(xmlReader.readXml()).doThrow(new IllegalArgumentException());

DeviceInfoHolderPopulator deviceInfoHolderPopulator  = new DeviceInfoHolderPopulator(xmlReader); 

//call testing method
boolean returned = spyDeviceInfoHolderPopulator.populateDeviceInfoHolder();

Assign.assignFalse(returned);

【讨论】:

  • 如果可以,你能解释一下我应该怎么写这个测试吗?
  • 我可以试试,如果你发布或解释你的测试方法做什么/应该做什么
  • 我想简单地在这个方法中抛出一个异常并验证它是否会返回false(这个方法是关于解析XML文件并且有很多try-catch语句)。如果 XML 文件损坏会发生什么。在这种情况下,该方法应该返回 false。这就是我要测试的。 (该应用程序适用于 android 所以我不能使用 JUnit4)
  • 非常感谢 Ikrnac。我完全理解你所说的。不是制作测试方法的间谍对象,而是有必要制作这个测试方法内部的类的间谍/模拟对象,它可以是任何东西。在这种情况下,将在测试方法中抛出异常。抱歉,我没有足够的评分来投票支持您提供的解决方案。
  • @sergey136 很高兴我提供了帮助。顺便说一句,您可以将我的一个答案标记为正确,这将给我 15 分,谢谢
【解决方案2】:

spy 的语法略有不同:

doThrow(toThrow).when(spyDeviceInfoHolderPopulator).populateDeviceInfoHolder();

在“监视真实物体的重要问题”部分阅读更多内容!这里:https://mockito.googlecode.com/svn/tags/latest/javadoc/org/mockito/Mockito.html#13

【讨论】:

  • 谢谢。使用这个例子,异常直接在测试中抛出,而我试图直接在方法中抛出它,以便方法返回不同的值。 (对不起,如果我写错了,最近刚安装了 Mockito 并开始使用测试替身)
  • spyDeviceInfoHolderPopulator.populateDeviceInfoHolder();调用应该抛出异常。我认为这是您想要实现的行为
  • 它应该抛出一个异常,但这个异常不应该在它自己的测试用例中抛出。因为现在我必须使用 try 和 catch 否则会失败
  • @sergey136 我不明白,抱歉。
  • 看Ikrnac。我想在测试时在方法中抛出异常。所以如果抛出异常,函数应该返回不同的值。让我们暂时忘记测试。例如,程序正在运行并开始执行此功能。但是,该函数引发了异常。我需要从中获取返回值,因为此函数的结果取决于下一个函数的结果。
【解决方案3】:

这里spy对象的创建不好。

创作应该是这样的

DeviceInfoHolderPopulator spyDeviceInfoHolderPopulator = spy(new DeviceInfoHolderPopulator());

然后在 spy 对象上存根你的方法。

参考:API

编辑:

这是来自 API。

Sometimes it's impossible or impractical to use Mockito.when(Object) for stubbing spies. 
Therefore for spies it is recommended to always 
use doReturn|Answer|Throw()|CallRealMethod family of methods for stubbing. 
Example:

List list = new LinkedList();
List spy = spy(list);

//Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)
when(spy.get(0)).thenReturn("foo");

//You have to use doReturn() for stubbing
doReturn("foo").when(spy).get(0);

【讨论】:

  • 这与答案中的间谍创建相同,只是压缩成一行。
  • @lkrnac 我很惊讶。与在新对象和现有对象上创建间谍有何相同?使用 API 中的文档更新了我的答案。不一样。您需要在答案中使用像 doThrow 这样的显式方法。但是创建无法模拟间谍功能的对象有什么用?我更喜欢继续在新对象上创建间谍,而不是创建然后强行抛出异常。
  • @downvoter,请评论一下上述答案有什么问题?它不会对 OP 的要求有正确的判断,还是它与上下文无关,还是错误的?我提供了 API 文档,哪些站点是概念证明。
  • 好吧,在我的情况下,doReturn 将返回 true 或 false(取决于我放在那里的内容)。但是我想在测试的方法中抛出一个异常来观察不同的函数返回。
  • DeviceInfoHolderPopulator deviceInfoHolderPopulator = new DeviceInfoHolderPopulator(); DeviceInfoHolderPopulator 间谍DeviceInfoHolderPopulator = 间谍(deviceInfoHolderPopulator); -> 这和你的创作一样
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-06
相关资源
最近更新 更多