Тестирование Java для поведения с Mockito

Я хочу протестировать java-метод, который имеет улучшенный доступ к нему с использованием Mockito. Проблема в том, что, когда я не знаю, как установить ожидания для расширенного для работы. Следующий код был получен из ответ без ответа в группе google google:

import static org.mockito.Mockito.when;
import static org.testng.Assert.assertTrue;

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

import org.mockito.Mockito;
import org.testng.annotations.Test;

public class ListTest
{

  @Test
  public void test()
  {
    List<String> mockList = Mockito.mock(List.class);
    Iterator<String> mockIterator = Mockito.mock(Iterator.class);

    when(mockList.iterator()).thenReturn(mockIter);
    when(mockIter.hasNext()).thenReturn(true).thenReturn(false);
    when(mockIter.next()).thenReturn("A");

    boolean flag = false;
    for(String s : mockList) {
        flag = true;
    }
    assertTrue(flag);
  }
} 

Код внутри цикла for никогда не выполняется. Установка ожиданий для итератора не работает, потому что расширение java для не использует итератор списка внутри. Установление ожиданий для метода List.get() не происходит ни потому, что расширение для реализации, похоже, не вызывает метод get() в списке.

Любая помощь будет очень оценена.

Ответ 1

Искривление итератора работает для меня. Пример кода ниже:

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.util.Collection;
import java.util.Iterator;

import org.junit.Before;
import org.junit.Test;

public class TestMockedIterator {

    private Collection<String> fruits;
    private Iterator<String> fruitIterator;

    @SuppressWarnings("unchecked")
    @Before
    public void setUp() {
        fruitIterator = mock(Iterator.class);
        when(fruitIterator.hasNext()).thenReturn(true, true, true, false);
            when(fruitIterator.next()).thenReturn("Apple")
            .thenReturn("Banana").thenReturn("Pear");

        fruits = mock(Collection.class);
        when(fruits.iterator()).thenReturn(fruitIterator);
    }

    @Test
    public void test() {
        int iterations = 0;
        for (String fruit : fruits) {
            iterations++;
        }
        assertEquals(3, iterations);
    }
}

Ответ 2

Если мне что-то не хватает, вы, вероятно, должны возвращать реальный список издевающихся значений. В этом случае создайте свой список тестовой строки методом генератора и просто верните это. В более сложных случаях вы можете заменить содержимое списка мечеными объектами.

В качестве заключительного момента я не могу себе представить, почему вам действительно понадобилось бы фальсифицировать расширенный цикл. Характер модульных испытаний не поддается хорошому уровню контроля. Это интересный вопрос.

Ответ 3

Просто хочу указать что-то, потому что я боролся с этим весь день:

Если вы хотите использовать синтаксис myList.forEach(...) вместо for(:), вы должны включить (там, где вы настроили ваш издевавшийся список):

doCallRealMethod().when(myMockedList).forEach(anyObject());

Ответ 4

Вы хотите сделать что-то вроде этого.

/**
    * THe mock you want to make iterable
    */
   @Mock
   javax.inject.Instance<Integer> myMockedInstanceObject;

   /**
     * Setup the myMockedInstanceObject mock to be iterable when the business logic
     * wants to loop existing instances of the on the iterable....
     */
    private void setupTransportOrderToTransportEquipmentMapperInstancesToBeIteratble() {
        // (a) create a very real iterator object
        final Iterator<Integer> iterator = Arrays
                .asList(Integer.valueOf(1), Integer.valueOf(2)).iterator();

        // (b) make sure your mock when looped over returns a proper iterator       
        Mockito.doAnswer(new Answer<Iterator<Integer>>() {
            @Override
            public Iterator<Integer> answer(InvocationOnMock invocation)
                    throws Throwable {
                return iterator;
            }
        }).when(myMockedInstanceObject).iterator();

    }

Линейные комменты и javadoc должны четко указывать, как издеваться над поведением любого итеративного, независимо от того, что это список, коллекцию javax.inject.instance или что-то еще.