如何在测试中模拟 CloseableIterator?

How to mock CloseableIterator in a test?

在我的实现中,我通过 ElasticsearchTemplate#stream() returns CloseableIterator<>.

从 ElasticSearch 获取数据

我想通过以下方式模拟此方法:

List<MyClass> foo = new ArrayList<>(); // and then I add some elements
when(mockTemplate.stream(any(SearchQuery.class), eq(MyClass.class))
 .thenReturn(foo.iterator());

iterator() returns Iterator<MyClass> 不是 CloseableIterator<MyClass> 我不知道如何转换它或找到解决方法。

来自 Spring 的

org.springframework.data.util.CloseableIterator.CloseableIterator 和来自 JDK 的 java.util.Iterator 是足够接近的接口:实际上 CloseableIteratorIterator 作为父接口。
这意味着您可以将 Iterator 替换为 CloseableIterator 但不能反过来:您需要什么。
虽然您不能在模拟记录中 return Iterator,但您仍然可以将 Iterator 转换为 CloseableIterator。由于方法委托,这不是很难,但它仍然需要少量样板文件。

示例:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.data.util.CloseableIterator;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;

@ExtendWith(MockitoExtension.class)
public class MockCloseableIteratorTest {

  @Mock
  ElasticsearchTemplate mockTemplateMock;

  @Test
  void foo() {
    List<String> foo = new ArrayList<>();
    // and then I add some elements
    Mockito.when(mockTemplateMock.stream(any(SearchQuery.class), eq(String.class)))
           .thenReturn(createCloseableIterator(foo.iterator()));

  }

  private <T> CloseableIterator<T> createCloseableIterator(Iterator<T> iterator) {
    return new CloseableIterator<T>() {
      @Override public void close() {
      }

      @Override public boolean hasNext() {
        return iterator.hasNext();
      }

      @Override public T next() {
        return iterator.next();
      }
    };
  }
}

对于那些使用 Kotlin 的人来说,以下是 createCloseableIterator 方法的语法:

    private fun <T> createCloseableIterator(iterator: Iterator<T>): CloseableIterator<T>? =
    object : CloseableIterator<T> {
        override fun close() {}
        override fun hasNext() = iterator.hasNext()
        override fun next() = iterator.next()
        override fun remove() {}
    }