模拟回调和获取参数值


88

我没有运气让Mockito捕获函数参数值!我在模拟搜索引擎索引,而不是建立索引,而是使用哈希。

// Fake index for solr
Hashmap<Integer,Document> fakeIndex;

// Add a document 666 to the fakeIndex
SolrIndexReader reader = Mockito.mock(SolrIndexReader.class);

// Give the reader access to the fake index
Mockito.when(reader.document(666)).thenReturn(document(fakeIndex(666))

我不能使用任意参数,因为我正在测试查询的结果(即查询返回的文档)。同样,我不想为每个文档指定特定值,也不想为每个文档都指定一行!

Mockito.when(reader.document(0)).thenReturn(document(fakeIndex(0))
Mockito.when(reader.document(1)).thenReturn(document(fakeIndex(1))
....
Mockito.when(reader.document(n)).thenReturn(document(fakeIndex(n))

我查看了“使用Mockito”页面上的回调部分。不幸的是,它不是Java,我无法对此做出自己的解释才能在Java中工作。

编辑(为澄清起见):如何获取Mockito捕获参数X并将其传递给我的函数?我想要传递给函数的X的确切值(或ref)。

我不想列举所有情况,并且任意参数将不起作用,因为我正在测试不同查询的不同结果。

Mockito页面上说

val mockedList = mock[List[String]]
mockedList.get(anyInt) answers { i => "The parameter is " + i.toString } 

那不是Java,我也不知道如何翻译成Java或将发生的任何事情传递给函数。


我不确定我是否完全了解您的失败。您的呼叫Mockito.when(reader.document(666)).thenReturn(document(fakeIndex(666))应为您设置模拟对象。打电话时会reader.document(666)怎样?
高度含咖啡因的2011年

666工作正常。但是,我希望能够传递一个特定的数字X并获得fakeIndex(X)的结果。我有大量潜在文档可以测试查询,因此我不想全部输入。
nflacco 2011年

Answers:


103

我从没用过Mockito,但是想学习,所以去了。如果某人比我更无知,请首先尝试他们的答案!

Mockito.when(reader.document(anyInt())).thenAnswer(new Answer() {
 public Object answer(InvocationOnMock invocation) {
     Object[] args = invocation.getArguments();
     Object mock = invocation.getMock();
     return document(fakeIndex((int)(Integer)args[0]));
     }
 });

2
我只是注意到右侧的Mockito链接:如何使方法返回传递给它的参数。看起来我很接近,即使没有发现。
Ed Staub,

良好的用户信誉(666)与原始问题相关!效果很好。我所做的只有东西才能编译的更改才在对象答案(InvocationOnMock调用)之前公开...
nflacco 2011年

54

查看ArgumentCaptors:

https://site.mockito.org/javadoc/current/org/mockito/ArgumentCaptor.html

ArgumentCaptor<Integer> argument = ArgumentCaptor.forClass(Integer.class);
Mockito.when(reader.document(argument.capture())).thenAnswer(
  new Answer() {
    Object answer(InvocationOnMock invocation) {
      return document(argument.getValue());
    }
  });

3
哇,我不知道您可以使用ArgumentCaptors进行存根。不过在该链接中有一个很大的警告。请谨慎操作。
einnocent

3
是的,你是对的。捕获程序仅应与验证一起使用。
qualidafial '16

41

您可能希望将verify()与ArgumentCaptor结合使用以确保在测试中执行,而ArgumentCaptor可以评估参数:

ArgumentCaptor<Document> argument = ArgumentCaptor.forClass(Document.class);
verify(reader).document(argument.capture());
assertEquals(*expected value here*, argument.getValue());

很明显,可以通过arguments.getValue()访问该参数的值,以进行进一步的操作/检查或执行任何您想执行的操作。


2
最佳答案:直截了当,易于理解
Radu Cugut

不回答问题。问题是关于Mockito.when,何时不验证。
seBaka28

@ seBaka28获取参数的最佳解决方案是参数捕获器。强烈建议Mockito的作者使用ArgumentCaptors进行验证,因此我想给出一个完整的观点答案。如果您自己选择不使用它们,那是您的选择,但不建议这样做。编辑:我不知道这如何证明是低票,但这也是您的选择。
fl0w

1
因为它不能回答问题。是的,当您要捕获参数时,ArgumentCaptor非常有用,但是您不能将其与when(...)。thenReturn()结合使用,这是OP试图执行的操作:基于特定参数,模拟服务应该返回一个特定的对象。
seBaka28

1
@YuraHoy,这是您使用verify时的标准错误消息,并且调用对象或方法的次数比您告诉validate所期望的要频繁。您可以通过添加times(n)参数来更改期望计数,如下所示:verify(reader,times(5))-这将需要5次交互。有关参考,请访问:baeldung.com/mockito-verify
fl0w

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.