Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing Java enhanced for behavior with Mockito

I want to test a java method that has an enhanced for on it using Mockito. The problem is that when I don't know how to set the expectations for the enhanced for to work. The following code was gotten from an unanswered question in the mockito google group:

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

The code inside the for loop never gets executed. Setting expectations for an iterator doesn't work, because the java enhanced for doesn't use the list iterator internally. Setting expectations for List.get() method doesn't either since the enhanced for implementation doesn't seem to call the get() method of the list either.

Any help will be much appreciated.

like image 692
HackerGil Avatar asked Jun 16 '11 22:06

HackerGil


People also ask

What is Mockito testing in Java?

Mockito is a java based mocking framework, used in conjunction with other testing frameworks such as JUnit and TestNG. It internally uses Java Reflection API and allows to create objects of a service. A mock object returns a dummy data and avoids external dependencies.

Is Mockito TDD or BDD?

Mockito uses the BDDMockito class that is available in the org. mockito package. It develops a test in BDD style. The BDD style of writing texts uses the //given //when //then comments as the primary part of the test body.

How can specify the mock Behaviour of an object in Java?

We can mock an object using @Mock annotation too. It's useful when we want to use the mocked object at multiple places because we avoid calling mock() method multiple times. The code becomes more readable and we can specify mock object name that will be useful in case of errors.

Which method does Mockito provides to add behavior of mock object?

Mockito adds a functionality to a mock object using the methods when(). Take a look at the following code snippet. //add the behavior of calc service to add two numbers when(calcService. add(10.0,20.0)).


2 Answers

Mocking the iterator works for me. See below code sample:

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);
    }
}
like image 68
hoipolloi Avatar answered Oct 15 '22 18:10

hoipolloi


Unless I am missing something, you should probably be returning a real list of mocked values. In this case, construct your list of test string in a generator method and simply return that. In more complex cases you can replace the contents of the list with mocked objects.

As a closing point, I can't imagine why you would ever really need to mock an enhanced for loop. The nature of unit tests don't lend themselves well to that level of inspection. It is an interesting question none the less.

like image 6
Andrew White Avatar answered Oct 15 '22 18:10

Andrew White