Ken Y-N
Ken Y-N

Reputation: 15009

Getting number of calls to a mock

Assume I want to test code like this:

class ClassToTest
  // UsedClass1 contains a method UsedClass2 thisMethod() {}
  UsedClass1 foo;
  void aMethod()
  {
    int max = new Random().nextInt(100);
    for(i = 0; i < max; i++)
    {
      foo.thisMethod().thatMethod();
    }
  }
}

If I have a test like this:

ClassToTest test;
UsedClass1 uc1;
UsedClass2 uc2;
@Test
public void thingToTest() {
  test = new ClassToTest();
  uc1 = mock(UsedClass1.class);
  uc2 = mock(UsedClass2.class);
  when(uc1.thisMethod()).thenReturn(uc2);
  when(uc2.thatMethod()).thenReturn(true);

  test.aMethod();

  // I would like to do this
  verifyEquals(callsTo(uc1.thisMethod()), callsTo(uc2.thatMethod()));
}

How can I get the number of calls to uc1.thisMethod() and uc2.thatMethod() so I can check they were both called the same number of times?

Upvotes: 7

Views: 14630

Answers (4)

Jakub Kubrynski
Jakub Kubrynski

Reputation: 14149

You can do something like this:

YourService serviceMock = Mockito.mock(YourService.class);

// code using YourService

// details of all invocations including methods and arguments
Collection<Invocation> invocations = Mockito.mockingDetails(serviceMock).getInvocations();
// just a number of calls of any mock's methods
int numberOfCalls = invocations.size();

If you want only the invocations of certain method/param combination you, you can do so with

int specificMethodCall = Mockito.mockingDetails(serviceMock.myMethod(myParam)).getInvocations()

Upvotes: 21

Chriss
Chriss

Reputation: 5629

You can use a custom VerificationMode to count the invocations, here you go:

public class InvocationCounter {

    public static <T> T countInvocations(T mock, AtomicInteger count) {
        return Mockito.verify(mock, new Counter(count));
    }

    private InvocationCounter(){}

    private static class Counter implements VerificationInOrderMode, VerificationMode {
        private final AtomicInteger count;

        private Counter(AtomicInteger count) {
            this.count = count;
        }

        public void verify(VerificationData data) {
            count.set(data.getAllInvocations().size());
        }

        public void verifyInOrder(VerificationDataInOrder data) {
            count.set(data.getAllInvocations().size());
        }

        @Override
        public VerificationMode description(String description) {
            return VerificationModeFactory.description(this, description);
        }

    }

}

And then use it like this (works also with void return types):

@Mock
private Function<String, Integer> callable;

AtomicInteger count= new AtomicInteger(); //here is the actual invocation count stored

countInvocations(callable,count).apply( anyString());

assertThat(count.get(),is(2));

Upvotes: 2

dkatzel
dkatzel

Reputation: 31648

If you know the number of times a method is suppoed to be called you can use the times() method of Mockito

//for example if had to be called 3 times
verify(uc1, times(3)).thisMethod();
verify(uc2, times(3)).thatMethod();

However, I now see that you call the method a random number of times, so this probably isn't the best answer unless you stub out the random number generator to always return an expected value.

Upvotes: 5

Antonio Barbuzzi
Antonio Barbuzzi

Reputation: 686

You could stub your methods, and increment a counter, like this:

final AtomicInteger countCall1 = new AtomicInteger();

Mockito.doAnswer(new Answer<UsedClass2>() {
    @Override
    public UsedClass2 answer(InvocationOnMock invocation) throws Throwable {
        countCall1.incrementAndGet();
        return uc2;
    }
}).when(uc1).thisMethod();

Upvotes: 11

Related Questions