How to mock CloseableIterator in a test?

Viewed 470

In my implementation I'm grabbing data from ElasticSearch via ElasticsearchTemplate#stream() which returns CloseableIterator<>.

I'd like to mock this method by doing:

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

but iterator() returns Iterator<MyClass> which is not CloseableIterator<MyClass> and I have no clue how to cast it or find a workaround.

2 Answers

org.springframework.data.util.CloseableIterator.CloseableIterator from Spring and java.util.Iterator from JDK are close enough interfaces : indeed CloseableIterator has Iterator as parent interface.
Which means that you can substitute a Iterator by a CloseableIterator but not the reverse : what you need.
While you cannot return an Iterator in your mock record, you can still convert an Iterator to a CloseableIterator. Which is not very hard thank to method delegation while it still requires a small amount of boilerplate.

Example :

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

For those working on Kotlin, following will be the syntax for createCloseableIterator method:

    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() {}
    }
Related