Counting method invocations in Unit tests

JavaUnit TestingMockitoJunit4Jmockit

Java Problem Overview


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

Java Solutions


Solution 1 - Java

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

Solution 2 - Java

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

Solution 3 - Java

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";
        }
    }
}

Solution 4 - Java

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);

Solution 5 - Java

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.

Solution 6 - Java

It sounds like you may want a test spy. See, for example, Mockito.spy().

Solution 7 - Java

You've got a few options

  1. Add some special code which counts invocations in the function. It will work, but it's not a great solution.

  2. After you run your unit tests, check the code coverage. Most coverage tools will count invocations but they are really designed for post-processing.

  3. Use a profiler. A profiler will let you count how many times a function is invoked. This is a very manual process so it's not really designed for unit testing.

A better solution would be to check that output is what you expect rather than checking how it works internally.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser855View Question on Stackoverflow
Solution 1 - Javacase nelsonView Answer on Stackoverflow
Solution 2 - JavaJakub KubrynskiView Answer on Stackoverflow
Solution 3 - JavaOlivierTerrienView Answer on Stackoverflow
Solution 4 - Javaoleh.kovaliukView Answer on Stackoverflow
Solution 5 - JavatolitiusView Answer on Stackoverflow
Solution 6 - JavaMichael Brewer-DavisView Answer on Stackoverflow
Solution 7 - JavaMark RobinsonView Answer on Stackoverflow