模拟第一次调用失败,第二次调用成功

jb.*_*jb. 101 java mockito

我想用Mockito测试下面的(简化)代码.我不知道如何告诉Mockito第一次失败,然后第二次成功.

for(int i = 1; i < 3; i++) {
  String ret = myMock.doTheCall();

  if("Success".equals(ret)) {
    log.write("success");
  } else if ( i < 3 ) {
    log.write("failed, but I'll try again. attempt: " + i);
  } else {
    throw new FailedThreeTimesException();
  }
}
Run Code Online (Sandbox Code Playgroud)

我可以设置成功测试:

Mockito.when(myMock).doTheCall().thenReturn("Success");
Run Code Online (Sandbox Code Playgroud)

并且失败测试:

Mockito.when(myMock).doTheCall().thenReturn("you failed");
Run Code Online (Sandbox Code Playgroud)

但是,我如何测试如果它失败一次(或两次)然后成功,那很好吗?

Jon*_*eet 218

来自文档:

有时我们需要为同一个方法调用使用不同的返回值/异常存根.典型的用例可能是模拟迭代器.Mockito的原始版本没有这个功能来促进简单的嘲笑.例如,可以使用Iterable或简单集合代替迭代器.那些提供了自然的存根方式(例如使用真实的集合).在极少数情况下,存根连续调用可能很有用,但是:

when(mock.someMethod("some arg"))
   .thenThrow(new RuntimeException())
  .thenReturn("foo");

//First call: throws runtime exception:
mock.someMethod("some arg");

//Second call: prints "foo"
System.out.println(mock.someMethod("some arg"));
Run Code Online (Sandbox Code Playgroud)

所以在你的情况下,你想要:

when(myMock.doTheCall())
   .thenReturn("You failed")
   .thenReturn("Success");
Run Code Online (Sandbox Code Playgroud)

  • 这使我指出正确的方向(谢谢)我的场景处理void方法 - 在这种情况下你需要使用替代样式...`doThrow(new RuntimeException()).doNothing().when(myMock) .doTheCall();` (19认同)

Daw*_*ica 34

写出你想要的最短的方式是

when(myMock.doTheCall()).thenReturn("Success", "you failed");
Run Code Online (Sandbox Code Playgroud)

当你提供thenReturn这样的多个参数时,每个参数最多只会被使用一次,最后一个参数除外,根据需要多次使用.例如,在这种情况下,如果您拨打4次电话,您将获得"成功","您失败","您失败","您失败".


ano*_*aut 19

由于与此相关的评论很难阅读,我将添加格式化的答案.

如果你试图用一个只抛出异常的void函数,然后是一个无行为步骤,那么你会做这样的事情:

Mockito.doThrow(new Exception("MESSAGE"))
            .doNothing()
            .when(mockService).method(eq());
Run Code Online (Sandbox Code Playgroud)

  • 我不是在谈论您的代码示例,而是在谈论您的解释。您说,“如果您尝试使用void函数执行此操作。您可能想要异常而不是没有行为的地方。然后您将执行以下操作:`。由于标点符号的含义,很难理解。我想您想说的是:“如果您尝试使用仅引发异常的void函数来执行此操作,然后执行无行为步骤,那么您将执行以下操作:`。让我知道这是否是您的意思,我们将很乐意编辑您的解释,以使您更清楚:) (2认同)

typ*_*rpr 6

要添加到这个这个答案,您还可以使用循环来链接模拟调用。如果您需要多次模拟同一事物或以某种模式模拟,这将非常有用。

例如(虽然很牵强):

import org.mockito.stubbing.Stubber;

Stubber stubber = doThrow(new Exception("Exception!"));
for (int i=0; i<10; i++) {
    if (i%2 == 0) {
        stubber.doNothing();
    } else {
        stubber.doThrow(new Exception("Exception"));
    }
}
stubber.when(myMockObject).someMethod(anyString());
Run Code Online (Sandbox Code Playgroud)


Moh*_*idy 6

我有一个不同的情况,我想void为第一次调用模拟一个函数并在第二次调用时正常运行它。

这对我有用:

Mockito.doThrow(new RuntimeException("random runtime exception"))
       .doCallRealMethod()
       .when(spy).someMethod(Mockito.any());
Run Code Online (Sandbox Code Playgroud)