Mockito 验证 lambda 被调用 n 次

Mockito verify lambda is called n-times

我需要测试一个 lambda 函数是否被服务实例调用了 n 次。

我有一个与存储库交互的服务 class,当从存储库检索数据时发生错误时,服务应该重试,直到达到最大重试次数,所以我实现如下:

interface Repository {
   Collection<String> getData();
}

public class RetryHelper<T> {

    private Integer retries;

    public RetryHelper(Integer retries) {
        this.retries = retries;
    }

    public interface Operation<T> {
        T doIt() throws Exception;
    }

    public T doWithRetry(Operation<T> operation) throws Exception {
        int remainRetries = retries;
        do {
            try {
                return operation.doIt();
            } catch (Exception e) {
                if (remainRetries == 0) {
                    throw e;
                }
                //TODO: wait before retry
                remainRetries--;
            }
        } while (true);
    }
}

class Service {
   @Inject
   Repository repo;

   private final RetryHelper<Collection<String>> retryHelper;

   public Collection<String> callService() {
        try {
            Collection<String> res = retryHelper.doWithRetry(() ->
                repo.getData());
            return res;
        } catch (Exception e) {
            throw (CustomException) e;
        }
   }

}

我需要使用 Mockito 进行测试,当发生错误时 repo.getData() 被调用了 n 次。我可以更改 Service 代码和 RetryHelper,因此我愿意接受建议。

我已经尝试按照教程和文档实施测试:

public class ServiceTest {

    @Inject
    Service service;

    @InjectMock
    Repository repository;

    @InjectMock
    RetryHelper<Collection<String>> retryHelper;


    @Captor
    ArgumentCaptor<RetryHelper.Operation<Collection<String>>> operation;

    @BeforeEach
    void init_mocks() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    void shouldRetryIfDataQueryFailsForNonFatalError() throws Exception {
        when(repository.getData())
            .thenThrow(new RuntimeException("Runtime Exception"));

        service.callService();

        verify(retryHelper).doWithRetry(operation.capture());

        verify(repository, times(2)).getData();

    }
}

测试失败并显示 getData() 从未被调用的消息。

我终于在不使用 Captor

的情况下找到了解决方案

public class ServiceTest {

    @Inject
    Service service;

    @InjectMock
    Repository repository;

    @Inject
    RetryHelper<Collection<String>> retryHelper;


    @Test
    void shouldRetryIfDataQueryFailsForNonFatalError() throws Exception {
        when(repository.getData())
            .thenThrow(new RuntimeException("Runtime Exception"));
        
        try {
           service.callService();
        } catch(Exception e) {
             verify(repository, times(2)).getData();
        }

    }
}