Mockito:等待与参数匹配的调用

Posted

技术标签:

【中文标题】Mockito:等待与参数匹配的调用【英文标题】:Mockito: wait for an invocation that matches arguments 【发布时间】:2014-05-21 13:43:58 【问题描述】:

我正在编写一个 selenium 测试并使用 mockito 验证服务器行为。具体来说,当单击按钮时,我想确保页面控制器调用我已模拟的依赖项上的特定方法。

因为是 selenium 测试,我需要等待 mock 在另一个线程中被调用,所以我使用了 mockito 超时。

verify(myMock, timeout(5000).times(1)).myMethod("expectedArg");

我遇到的问题是 myMethod 被多次调用......而不是等待与预期参数匹配的调用,超时只等待第一次调用。 如果我使用 Thread.sleep(50000) 而不是 timeout(50000),它会按预期工作......但这很脏,所以我希望避免它。

如何等待使用预期输入调用 myMethod?

【问题讨论】:

【参考方案1】:

如果您能够设置预期的固定调用次数,则可以使用ArgumentCaptor

import static org.hamcrest.CoreMatchers.hasItem;

@Captor ArgumentCaptor<String> arg;

@Before
public void setUp() throws Exception 
    // init the @Captor
    initMocks(this);


@Test
public void testWithTimeoutCallOrderDoesntMatter() throws Exception 
    // there must be exactly 99 calls
    verify(myMock, timeout(5000).times(99)).myMethod(arg.capture());
    assertThat(arg.getAllValues(), hasItem("expectedArg"));

另一种方法是指定要验证的所有预期值,但需要按照调用它们的确切顺序提供这些值。与上述解决方案的不同之处在于,即使使用一些未经验证的参数额外调用了模拟,这也不会失败。换句话说,不需要知道总调用次数。代码示例:

@Test
public void testWithTimeoutFollowingCallsDoNotMatter() throws Exception 
    // the order until expected arg is specific
    verify(callback, timeout(5000)).call("firstExpectedArg");
    verify(callback, timeout(5000)).call("expectedArg");
    // no need to tell more, if additional calls come after the expected arg
    // verify(callback, timeout(5000)).call("randomArg");

【讨论】:

它甚至不需要成为参数捕获者。任何参数匹配器都适用于 timeout 函数。【参考方案2】:

这不是一个超级干净的解决方案,但您可以这样做(XX 是此处假定的返回类型):

final CountDownLatch latch = new CountDownLatch(1);

doReturn(new Answer<XX>()
    
        @Override
        public XX answer(InvocationOnMock invocation)
        
            latch.countDown();
            return someInstanceOfXX;
        
    
).when(myMock).myMethod("expectedArg");

然后,要测试是否调用了该方法,请执行以下操作:

try 
    assertTrue(latch.await(5L, TimeUnit.SECONDS));
 catch (InterruptedException e) 
    // Urgh... Failed. Deal with it and:
    Thread.currentThread.interrupt();

【讨论】:

这是一个非常聪明的方法!但这是一个非常简单的测试,我想我更愿意在验证之上做一个 thread.sleep 而不是增加这种程度的复杂性。 thread.sleep 很脏,但它很容易理解,并且包含在一组长时间运行的测试中。 是的,但你说它被多次调用...验证的结果将是方法的第一次调用,不一定是你感兴趣的那个。 嗯,我可能太习惯InOrder ;) 嗯,也许你应该在邮件列表中询问这个问题? 这是一个见仁见智的问题,但如果将Answer 提取到它自己的类中,它可能会使测试更具可读性。也许将它包装成一个具有描述性名称的静态方法。例如,我遇到过这种情况,尽管这是最低限度:javaape.wordpress.com/2010/03/17/…

以上是关于Mockito:等待与参数匹配的调用的主要内容,如果未能解决你的问题,请参考以下文章

OCHamcrest 匹配器参数与验证时的 Mockito 模拟不兼容

mockito doReturn精确匹配对象实例

Mockito org.mockito.exceptions.misusing.InvalidUseOfMatchersException:参数匹配器的使用无效!预期 0 个匹配器,记录 1 个:

单元测试mockito参数匹配使用场景和注意项

学习单元测试 Mockito 一篇文章就够了

mockito 验证未使用参数调用的方法