【问题标题】:Best practices for verifying recursive method calls with Mockito使用 Mockito 验证递归方法调用的最佳实践
【发布时间】:2013-04-05 13:30:17
【问题描述】:

考虑这个示例类:

public class Processor {
  private final Dependency dependency;

  public Processor(Dependency dependency) {
    this.dependency = dependency;
  }

  public void processUsers(List<Integer> userIds, int attempt) {
    if (attempt == 0) {
      //log initial processing
    } else if (attempt > 0 && attempt < 5) {
      //log retry processing
    } else {
      //log processing limit exceeded
      return;
    }
    List<Integer> failedIds = new ArrayList<Integer>();
    for (Integer userId : userIds) {
      try {
        processUser(userId);
      } catch (Exception ex) {
        //logging
        failedIds.add(userId);
      }
    }
    if (failedIds.isEmpty()) {
      //log ok
    } else {
      processUsers(failedIds, attempt + 1);
    }
  }

  public void processUser(Integer userId) throws Exception{
    //dependency can throw exception
    dependency.call();
  }
}

我想验证方法processUsers 在抛出异常时调用自身。 这是我的暴躁测试:

public class ProcessorTest {
  @Test
  public void processShouldCallItselfWithFailedSublistWhenProcessingFails(){
    Dependency dependency = mock(Dependency.class);
    when(dependency.call()).thenThrow(Exception.class);
    Processor processor = new Processor(dependency);
    processor.processUsers(Arrays.asList(new Integer[]{1,2,3}), 0);
    //need to verify processor will call #processUsers recursively
    //because the dependency thrown Exception, how?
  }
}

在某些情况下验证该方法以递归方式调用自身的最佳做法是什么?

我正在使用 TestNG + Mockito 和这种称为 JAVA 的冗长语言

【问题讨论】:

  • 依赖真的不用userId参数吗?
  • 确实如此,只是实际使用的一个例子

标签: java unit-testing mocking mockito


【解决方案1】:

您可以验证调用dependency.call() 的次数。这会告诉您重试有效 - 仅通过调用次数:

@Test
public void processShouldCallItselfWithFailedSublistWhenProcessingFails() {
    Dependency dependency = mock(Dependency.class);
    when(dependency.call()).thenReturn(1, 2).thenThrow(Exception.class).
        thenReturn(4);
    Processor processor = new Processor(dependency);
    processor.processUsers(Arrays.asList(new Integer[]{1, 2, 3}), 0);
    verify(dependency, times(4)).call();
}

这会告诉你重试最终失败了,异常太多:

@Test
public void processShouldFailAfterTooManyRetries() {
    Dependency dependency = mock(Dependency.class);
    when(dependency.call()).thenThrow(Exception.class);
    Processor processor = new Processor(dependency);
    final List<Integer> userIds = Arrays.asList(new Integer[]{1, 2, 3});
    final int expectedRetries = 5;
    processor.processUsers(userIds, 0);
    verify(dependency, times(expectedRetries * userIds.size())).call();
}

如果对依赖项的调用实际上使用了 userId,那么您实际上可以检查对 dependency.call(int userId) 的所有预期调用是否发生。这会告诉你,如果重试次数足够多,它们都经历了:

@Test
public void processShouldCallItselfWithFailedSublistWhenProcessingFails() {
    Dependency dependency = mock(Dependency.class);
    when(dependency.call(anyInt())).
        thenReturn(1, 2).thenThrow(Exception.class).thenReturn(4);
    Processor processor = new Processor(dependency);
    processor.processUsers(Arrays.asList(new Integer[]{1, 2, 3}), 0);
    verify(dependency).call(1);
    verify(dependency).call(2);
    verify(dependency, times(2)).call(3);
}

@Test
public void processShouldFailAfterTooManyRetries() {
    Dependency dependency = mock(Dependency.class);
    when(dependency.call(anyInt())).thenThrow(Exception.class);
    Processor processor = new Processor(dependency);
    final List<Integer> userIds = Arrays.asList(new Integer[]{1, 2, 3});
    final int expectedRetries = 5;
    processor.processUsers(userIds, 0);
    for (Integer userId : userIds) {
        verify(dependency, times(expectedRetries)).call(userId);
    }
}

【讨论】:

    【解决方案2】:

    不确定最佳实践,但您可以通过验证方法被调用的次数来达到同样的效果

     int invocationCount = 5; // Or any other desired number
     verify(processor,times(invocationCount)).processUsers();
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-24
    • 2014-12-20
    • 1970-01-01
    • 1970-01-01
    • 2011-02-13
    • 1970-01-01
    • 2015-10-20
    相关资源
    最近更新 更多