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

Posted

技术标签:

【中文标题】模拟第一次调用失败,第二次调用成功【英文标题】:Simulate first call fails, second call succeeds 【发布时间】:2012-07-31 21:34:08 【问题描述】:

我想使用 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();
  

我可以设置成功测试:

Mockito.when(myMock).doTheCall().thenReturn("Success");

失败测试:

Mockito.when(myMock).doTheCall().thenReturn("you failed");

但是我如何测试如果它失败一次(或两次)然后成功,就可以了?

【问题讨论】:

【参考方案1】:

来自the docs:

有时我们需要为同一个方法调用使用不同的返回值/异常存根。典型的用例可能是模拟迭代器。原始版本的 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"));

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

when(myMock.doTheCall())
   .thenReturn("You failed")
   .thenReturn("Success");

【讨论】:

这为我处理 void 方法的场景指明了正确的方向(感谢)——在这种情况下,您需要使用替代样式...doThrow(new RuntimeException()).doNothing().when(myMock).doTheCall();【参考方案2】:

写你想要的东西的最短方法是

when(myMock.doTheCall()).thenReturn("Success", "you failed");

当您像这样向thenReturn 提供多个参数时,每个参数将最多使用一次,除了最后一个参数,它会根据需要使用多次。例如,在这种情况下,如果您拨打 4 次电话,您将获得“成功”、“您失败”、“您失败”、“您失败”。

【讨论】:

【参考方案3】:

由于与此相关的评论难以阅读,我将添加一个格式化的答案。

如果您尝试使用仅引发异常的 void 函数执行此操作,然后执行无行为步骤,那么您可以执行以下操作:

Mockito.doThrow(new Exception("MESSAGE"))
            .doNothing()
            .when(mockService).method(eq());

【讨论】:

【参考方案4】:

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

这对我有用:

Mockito.doThrow(new RuntimeException("random runtime exception"))
       .doCallRealMethod()
       .when(spy).someMethod(Mockito.any());

【讨论】:

【参考方案5】:

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

例如(虽然有点牵强):

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());

【讨论】:

我其实不知道这个 Stubber 并发现它很有用,+1。 如果您需要调用 void 方法,这应该是正确的答案。【参考方案6】:

最短的应该是

doReturn("Fail", "Success").when(myMock).doTheCall();

【讨论】:

以上是关于模拟第一次调用失败,第二次调用成功的主要内容,如果未能解决你的问题,请参考以下文章

WCF 客户端。客户证书。第一次调用成功,第二次调用失败

Spring Method Level Security 在第二次调用时失败

gitlab第一次推送成功第二次失败

谷歌游戏服务登录问题(第一次尝试失败,第二次成功)

fread()函数第一次读取成功,但第二次读取失败,为啥为啥为啥,

小程序第一次登录失败,第二次成功问题(2)