Counting method invocations in Unit tests

What is the best way to count method invocations in a Unit Test. Do any of the testing frameworks allow that?


It sounds like you may want to be using the .expects(1) type methods that mock frameworks usually provide.

Using mockito, if you were testing a List and wanted to verify that clear was called 3 times and add was called at least once with these parameters you do the following:

List mock = mock(List.class);        
someCodeThatInteractsWithMock();                 

verify(mock, times(3)).clear();
verify(mock, atLeastOnce()).add(anyObject());      

Source - MockitoVsEasyMock


In Mockito 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();

You can count number of method invocation by using interface Answer in Mockito.

ConnectionPool mockedConnectionPool = mock(ConnectionPool.class);

    final int[] counter = new int[1];

    when(mockedConnectionPool.getConnection()).then(new Answer<Connection>() {

        @Override
        public Connection answer(InvocationOnMock invocation) throws Throwable {
            counter[0]++;
            return conn;
        }

    }); 
    // some your code

    assertTrue(counter[0] == 1);

Given an example class "RoleRepository" with a single method "getRole(String user)" which would return a role.

Assuming you have declared this object as Mock or Spy and you want to check whether the method getRole(String) is called for once a time.

You would do something like: Mockito.verify(roleRepository, Mockito.times(1)).getRole(Mockito.anyString());

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class RoleRepositoryTest {

    @Spy
    private RoleRepository roleRepository = new RoleRepository();

    @Test
    public void test() {
        roleRepository.getRole("toto");
        Mockito.verify(roleRepository, Mockito.times(1)).getRole(Mockito.anyString());
    }

    public static class RoleRepository {

        public String getRole(String user) {
            return "MyRole";
        }
    }
}

Depending on what methods you want to count, you can create a test config, with a @Before advice matching your class / package / method:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class MethodCounterAspect {

    private int counter = 0 // or inject the Counter object into this aspect

    @Pointcut( "execution( * com.sample.your.package.*.*(..) )" )
    public void methodsToCount() {}

    @Before("methodsToCount()")
    public void execute() throws Throwable {
        counter++; // or update the counter injected into this aspect..
    }

    // get the counter
}

You can use vanilla AspectJ or Spring AOP via above or XML configs if you find it easier.

You can create different pointcuts / aspect if you need to.