49

I'm writing a selenium test and verifying the server behavior with mockito. Specifically, when a button is clicked, I want to make sure the page controller calls a particular method on a dependency which I've mocked.

Because it is a selenium test, I need to wait for the mock to be invoked in another thread, so I'm using mockito timeout.

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

The trouble that I'm having is that myMethod is called many times... rather than waiting for an invocation that matches the expected arguments, timeout only waits for the first invocation. If I use Thread.sleep(50000) rather than timeout(50000), it works as expected... but that's dirty so I'm hoping to avoid it.

How do I wait for myMethod to be invoked with the expected input?

Bryan Hart
  • 583
  • 1
  • 5
  • 11

2 Answers2

60

If you are able to set a fixed number of calls to expect, it can be done with an 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"));
}

Another way is to specify all the expected values to verify, but those need to be provided in the exact order that they are invoked. The difference to the above solution is that this doesn't fail even if the mock is additionally called with some non-verified arguments. In other words, no need to know the number of total invocations. Code example:

@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");
}
juhoautio
  • 1,541
  • 1
  • 22
  • 23
21

This is not a super clean solution but you can do this (XX is the supposed return type here):

final CountDownLatch latch = new CountDownLatch(1);

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

Then, to test if the method is called, do:

try {
    assertTrue(latch.await(5L, TimeUnit.SECONDS));
} catch (InterruptedException e) {
    // Urgh... Failed. Deal with it and:
    Thread.currentThread().interrupt();
}
E Ciotti
  • 4,740
  • 1
  • 25
  • 17
fge
  • 119,121
  • 33
  • 254
  • 329
  • this is a pretty clever method! but this is a pretty simple test, I think I'd prefer to do a thread.sleep above the verify rather than adding this degree of complexity. thread.sleep is dirty, but its easy to understand and its in a suite of long-running tests. – Bryan Hart Apr 08 '14 at 17:56
  • Yes but you say it is invoked more than once... The result from the verification will be the first invocation of the method, not necessarily the one you are interested in. – fge Apr 08 '14 at 17:58
  • That doesn't seem to be the case, it verifies that there is exactly one invocation that matches the expected arguments. I used an ArgumentMatcher to check, and even though it was invoked many times, as long as the matcher only returned true once it passes. `Thread.sleep(5000); verify(myMock, times(1)).myMethod("expectedArg");` I was hoping there was a simple way to do this in mockito so I could avoid Thread.Sleep – Bryan Hart Apr 08 '14 at 18:40
  • 1
    Hmmyeah, I'm probably too used to `InOrder` ;) – fge Apr 08 '14 at 18:46
  • Yeah, this is why I'm so confused... It works with the sleep... but using mockito timeout rather than sleep will break it. – Bryan Hart Apr 08 '14 at 18:50
  • 1
    Uhm, maybe you should ask about this on the mailing lists? – fge Apr 08 '14 at 18:52
  • Obviously you don't care about the speed so much in this case, but let it be noted that a `CountDownLatch` based solution is slightly faster, than `Mockito.timeout`. `timeout` uses a 10ms polling delay (default), while `CountDownLatch` has immediate response via `Object.notify`. – juhoautio Jun 02 '14 at 21:42
  • 1
    It's a matter of opinion, but it might make the test more readable if the `Answer` is extracted into a class of its own. Maybe wrap it into a static method with a descriptive name. I've come across this, for example, although this is the bare minimum: http://javaape.wordpress.com/2010/03/17/avoid-thread-sleep-in-concurrency-tests/#highlighter_41281 – juhoautio Jun 02 '14 at 21:46