计算单元测试中的方法调用

计算单元测试中方法调用的最佳方法是什么。有哪个测试框架允许这样做吗?

113392 次浏览

你有几个选择

1)添加一些特殊的代码来计算函数中的调用。会有用的,但不是个好办法。

2)运行单元测试后,检查代码覆盖率。大多数覆盖工具将计算调用,但它们实际上是为后处理而设计的。

3)使用分析器。探查器将允许您计算调用函数的次数。这是一个非常手工的过程,所以它并不是真正为单元测试而设计的。

一个更好的解决方案是检查输出是否符合您的预期,而不是检查它在内部是如何工作的。

听起来你可能想要一个 测试间谍。看,例如,Mockito 间谍

根据您想要计数的方法,您可以创建一个测试配置,其中包含与您的 class/package/method 相匹配的 @Before通知:

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
}

您可以通过上面的配置使用普通的 AspectJ 或 SpringAOP,如果您觉得更容易的话,也可以使用 XML 配置。

如果需要,可以创建不同的切入点/方面。

听起来您可能想要使用模拟框架通常提供的 .expects(1)类型方法。

如果你正在测试一个 List,想要验证 clear 被调用了3次,add 被调用了至少一次,使用这些参数,你可以执行以下操作:

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


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

资料来源 -MockitoVsEasyMock

在 Mockito,你可以使用 interface Answer 来计算方法调用的次数。

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

在 Mockito 你可以这样做:

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

给定一个示例类“ RoleRepository”,其中只有一个方法“ getRole (String user)”,该方法将返回一个角色。

假设您已经将这个对象声明为 Mock 或 Spy,并且希望检查是否每次调用方法 getRole (String)。

你可以这样做: 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";
}
}
}