What is the best way to count method invocations in a Unit Test. Do any of the testing frameworks allow that?
问题:
回答1:
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 parameter you do the following:
List mock = mock(List.class);
someCodeThatInteractsWithMock();
verify(mock, times(3)).clear();
verify(mock, atLeastOnce()).add(anyObject());
(From http://code.google.com/p/mockito/wiki/MockitoVSEasyMock)
回答2:
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();
回答3:
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);
回答4:
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.
回答5:
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";
}
}
}
回答6:
It sounds like you may want a test spy. See, for example, Mockito.spy().
回答7:
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.