Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 220
Ken Y-N Avatar asked Aug 28 '14 07:08

Ken Y-N


4 Answers

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()
like image 83
Jakub Kubrynski Avatar answered Sep 21 '22 14:09

Jakub Kubrynski


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();
like image 40
antoniob Avatar answered Sep 18 '22 14:09

antoniob


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.

like image 27
dkatzel Avatar answered Sep 20 '22 14:09

dkatzel


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));
like image 44
Chriss Avatar answered Sep 19 '22 14:09

Chriss