71

在单元测试中计算方法调用的最佳方法是什么。是否有任何测试框架允许这样做?

4

7 回答 7

89

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

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

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

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

来源-MockitoVsEasyMock

于 2011-10-08T17:25:37.370 回答
47

在 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();
于 2016-08-13T13:29:30.457 回答
9

您可以使用 Mockito 中的接口 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);
于 2013-12-27T15:23:31.963 回答
9

给定一个示例类“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";
        }
    }
}
于 2018-01-25T09:01:50.933 回答
4

根据您要计算的方法,您可以创建一个测试配置,并@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
}

如果您发现它更容易,您可以通过上述或 XML 配置使用 vanilla AspectJ 或 Spring AOP。

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

于 2011-10-08T06:32:23.190 回答
3

听起来您可能想要一个测试间谍。例如,参见Mockito.spy()

于 2011-10-08T06:22:05.713 回答
1

你有几个选择

1)添加一些特殊代码来计算函数中的调用。它会起作用,但这不是一个很好的解决方案。

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

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

更好的解决方案是检查输出是否符合您的预期,而不是检查其内部工作方式。

于 2011-10-08T05:41:34.853 回答