Java 如何让 Mockito 模拟按顺序执行不同的操作?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20098607/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 23:09:11  来源:igfitidea点击:

How can I make a Mockito mock perform different actions in sequence?

javamockito

提问by Michael Wiles

The following code:

以下代码:

  ObjectMapper mapper = Mockito.mock(ObjectMapper.class);
  Mockito.doThrow(new IOException()).when(mapper).writeValue((OutputStream) Matchers.anyObject(), Matchers.anyObject());
  Mockito.doNothing().when(mapper).writeValue((OutputStream) Matchers.anyObject(), Matchers.anyObject());

  try {
      mapper.writeValue(new ByteArrayOutputStream(), new Object());
  } catch (Exception e) {
      System.out.println("EXCEPTION");
  }

  try {
      mapper.writeValue(new ByteArrayOutputStream(), new Object());
  } catch (Exception e) {
      System.out.println("EXCEPTION");
  }

The expected output is

预期的输出是

EXCEPTION

例外

right?

对?

But I get nothing

但我一无所获

If I then make the doThrow after the doNothing I get

如果我在 doNothing 之后做 doThrow 我得到

EXCEPTION
EXCEPTION

例外
例外

So It looks like it is the last mock that is the one that is taken... I thought it would take the mocks in the order they're registered?

所以看起来它是最后一个被采用的模拟......我认为它会按照它们注册的顺序进行模拟?

I'm looking to produce a mock throws the exception first time and completes normally the second time...

我正在寻找一个模拟,第一次抛出异常并第二次正常完成......

采纳答案by Jeff Bowman

Mockito can stub consecutive behavior with the same parameters—forever repeating the final instruction—but they all have to be part of the same "chain". Otherwise Mockito effectively thinks you've changed your mind and overwrites your previously-mocked behavior, which isn't a bad feature if you've established good defaults in a setUpor @Beforemethod and want to override them in a specific test case.

Mockito 可以用相同的参数存根连续的行为——永远重复最后的指令——但它们都必须是同一个“链”的一部分。否则 Mockito 会有效地认为您改变了主意并覆盖了您之前被嘲笑的行为,如果您在 a setUpor@Before方法中建立了良好的默认值并希望在特定测试用例中覆盖它们,这不是一个坏功能。

The general rules for "which Mockito action will happen next":The most-recently-defined chainthat matches all arguments will be selected. Within the chain, each action will happen once (counting multiple thenReturnvalues if given like thenReturn(1, 2, 3)), and then the last action will be repeated forever.

对于“该行动的Mockito接下来将发生”的一般规则:近期被定义的最链,所有的参数匹配将被选中。在链中,每个动作都会发生一次(thenReturn如果给定像thenReturn(1, 2, 3),则计算多个值),然后最后一个动作将永远重复。

// doVerb syntax, for void methods and some spies
Mockito.doThrow(new IOException())
    .doNothing()
    .when(mapper).writeValue(
        (OutputStream) Matchers.anyObject(), Matchers.anyObject());

This is the equivalent of chained thenVerbstatements in the more-common whensyntax, which you correctly avoided here for your voidmethod:

这相当于thenVerb更常见when语法中的链式语句,您在此处正确避免了您的void方法:

// when/thenVerb syntax, to mock methods with return values
when(mapper.writeValue(
        (OutputStream) Matchers.anyObject(), Matchers.anyObject())
    .thenThrow(new IOException())
    .thenReturn(someValue);

Note that you can use static imports for Mockito.doThrowand Matchers.*, and switch to any(OutputStream.class)instead of (OutputStream) anyObject(), and wind up with this:

请注意,您可以对Mockito.doThrowand使用静态导入Matchers.*,然后切换到any(OutputStream.class)而不是(OutputStream) anyObject(),最后得到以下结果:

// doVerb syntax with static imports
doThrow(new IOException())
    .doNothing()
    .when(mapper).writeValue(any(OutputStream.class), anyObject());

See Mockito's documentation for Stubberfor a full list of commands you can chain.

有关可以链接的完整命令列表,请参阅Mockito 的 Stubber 文档