【问题标题】:Counting method invocations in Unit tests计算单元测试中的方法调用
【发布时间】:2011-12-03 10:41:07
【问题描述】:

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

【问题讨论】:

  • 您能详细说明您要做什么吗?您是否正在尝试测量代码覆盖率?表现?效率?
  • 并非如此。只想检查当我调用 testXXX() 测试方法时,类上的该方法 foo() 至少被调用 N 次。
  • 这不可能吗?我知道 Mocking 框架允许我断言 Mock 对象的调用计数。难道不能在实物上做吗?

标签: unit-testing junit4 mockito jmockit


【解决方案1】:

听起来您可能想要test spy。例如,请参阅Mockito.spy()

【讨论】:

  • Mockito.spy() 链接似乎已损坏
【解决方案2】:

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

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

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

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

来源 - MockitoVsEasyMock

【讨论】:

    【解决方案3】:

    给定一个示例类“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";
            }
        }
    }
    

    【讨论】:

      【解决方案4】:

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

      【讨论】:

      • 我发现这是最简单、最有效的方法,您可以访问模拟对象。
      • 感谢 Jakub,它也很好,因为如果您检查对象,您可以看到调用的位置和函数。
      • 得到所有的调用。应该是一种获取单个方法调用的方法,无需流式传输和过滤该集合并使用反射将Method 对象设置为equal。 Think Sinon 的 JS API:stub.callCount
      【解决方案5】:

      您可以使用 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);
      

      【讨论】:

        【解决方案6】:

        根据您要计算的方法,您可以创建一个测试配置,并使用与您的类/包/方法匹配的 @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。

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

        【讨论】:

        • 如果您只想查看调用次数,这就是执行此操作的方法。如果你想验证调用,mock 框架通常用断言为你包装这个模式。请参阅我对模拟版本的回答。
        • 问题是“在单元测试中计算方法调用的最佳方法是什么”。以上将允许您这样做 => 在单元/集成测试中计算方法调用,而不会污染测试本身。
        • 我同意,这就是我投票给你的原因。但是在 cmets 中,作者询问了关于断言真实对象与模拟对象的调用计数。如果他想实际测试调用,他应该使用模拟库,因为它们就是为此而构建的。
        【解决方案7】:

        你有几个选择

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

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

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-12-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-10
          相关资源
          最近更新 更多