Here's the sample code that fails:
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Mockito;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;
public class TestMulti {
private static interface TestInterface {
int foo(String threadName, int count);
}
@Test
public void testSharedMock() throws InterruptedException {
final CountDownLatch start = new CountDownLatch(1);
final CountDownLatch stop = new CountDownLatch(1);
final int numThreads = 2;
final long TIMEOUT = 2000;
final TestInterface mock = Mockito.mock(TestInterface.class);
Thread[] threads = new Thread[numThreads];
final int[] counts = new int[numThreads];
for (int i = 0; i < numThreads; i++) {
final String name = "Thread:" + i;
final int finalI = i;
Thread t = new Thread(name) {
@Override
public void run() {
try {
start.await();
long t1 = System.currentTimeMillis();
int count = 0;
while (System.currentTimeMillis() - t1 < TIMEOUT) {
count++;
doReturn(count).when(mock).foo(name, count);
verify(mock, never()).foo(name, count);
assertEquals(count, mock.foo(name, count));
verify(mock).foo(name, count);
}
counts[finalI] = count;
System.out.println(name + " did " + count + " iterations");
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
stop.countDown();
}
}
};
threads[i] = t;
t.start();
}
start.countDown();
stop.await();
int totalCount = 0;
for (int i = 0; i < numThreads; i++) {
final String name = "Thread:" + i;
int count = counts[i];
totalCount += count;
InOrder order = inOrder(mock);
for (int j = 0; j < count; j++) {
order.verify(mock).foo(name, 1 + j);
}
verify(mock, times(count)).foo(eq(name), anyInt());
}
System.out.println("Total count: " + totalCount);
}
}
Due to the undeterministic behaviour, this can error with multiple problems, including:
- Exception in thread "Thread:1" java.lang.NullPointerException
at org.mockito.internal.stubbing.MockitoStubber.findAnswerFor(MockitoStubber.java:63) - Exception in thread "Thread:1" java.lang.AssertionError: expected:<1> but was:<0>
- Exception in thread "Thread:1" org.mockito.exceptions.misusing.UnfinishedVerificationException:
Missing method call for verify(mock) here: - Exception in thread "Thread:0" org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at TestMulti$1.run(TestMulti.java:43) - Exception in thread "Thread:0" java.util.ConcurrentModificationException
at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:761)
at java.util.LinkedList$ListItr.next(LinkedList.java:696)
at org.mockito.internal.stubbing.MockitoStubber.findAnswerFor(MockitoStubber.java:62) - Exception in thread "Thread:0" java.util.ConcurrentModificationException
at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:761)
at java.util.LinkedList$ListItr.next(LinkedList.java:696)
at org.mockito.internal.stubbing.MockitoStubber.findAnswerFor(MockitoStubber.java:62) - Exception in thread "Thread:0" java.lang.NullPointerException
at java.util.concurrent.ConcurrentLinkedQueue.offer(ConcurrentLinkedQueue.java:190)
at java.util.concurrent.ConcurrentLinkedQueue.add(ConcurrentLinkedQueue.java:180)
at org.mockito.internal.stubbing.StubbedInvocationMatcher.addAnswer(StubbedInvocationMatcher.java:34)