Ложный сплитератор для реализации Iterable, когда вызывается несколько раз? - PullRequest
0 голосов
/ 04 июля 2018

У меня проблема с насмешкой над классом Iterable в сочетании с вызовом spliterator(). Все работает нормально при вызове spliterator один раз, но второй вызов не возвращает значений.

Поскольку макет всегда возвращает один и тот же экземпляр Spliterator, я предполагаю, что состояние не сбрасывается. Есть ли способ сделать это?

Это самый маленький пример, который я могу привести

Звонок mapStringToHash - это Либ в реальной жизни, и его нельзя изменить. MyIterable также не находится под моим контролем.

package net.test;

import static org.hamcrest.CoreMatchers.is;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static java.util.stream.Collectors.toList;
import static org.hamcrest.MatcherAssert.assertThat;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Spliterator;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class SpliteratorTest {

    class MyIterable<T> implements Iterable<T> {

        private List<T> list;

        MyIterable(List<T> list) {
            this.list = new ArrayList<>(list);
        }

        @Override
        public Iterator<T> iterator() {
            return list.iterator();
        }

        @Override
        public Spliterator<T> spliterator() {
            return list.spliterator();
        }
    }

    // this a library method
    private Stream<Integer> mapStringToHash(final MyIterable<String> myIterable) {
        return StreamSupport.stream(myIterable.spliterator(), false).map(String::hashCode);
    }

    @Test
    public void testSeveralSpliteratorCalls() {
        MyIterable myIterable = givenMyIterableMock("a", "b", "c");

        Stream<Integer> myIterableHash1 = mapStringToHash(myIterable);
        assertThat(myIterableHash1.count(), is(3L));


        Stream<Integer> myIterableHash2 = mapStringToHash(myIterable);
        assertThat(myIterableHash2.count(), is(3L));
    }

    private MyIterable givenMyIterableMock(String... values) {
        MyIterable myIterable = mock(MyIterable.class);

        Spliterator myIterableSpliterator = Arrays.stream(values)
                .collect(toList())
                .spliterator();
        doReturn(myIterableSpliterator).when(myIterable).spliterator();
        return myIterable;
    }
}

1 Ответ

0 голосов
/ 04 июля 2018

Оказывается, это не так уж и обходно, как я думал. Это можно сделать с помощью пользовательской реализации Answer, но, поскольку Answer является функциональным интерфейсом, достаточно следующее:

Mockito.when(myIterable.spliterator()).then(invocation -> Arrays.spliterator(values));
...