Mock the enhanced for loop

4,351 views
Skip to first unread message

mikaelpe...@gmail.com

unread,
Aug 22, 2013, 1:12:52 AM8/22/13
to moc...@googlegroups.com
Hi,

We have the following code:

List<String> tm = new ArrayList<String>();

.....

public void thisMethodSetsTm(){

    tm  = getActiveTm();
}

public List<String> getActiveTm(){
....

}

public void setState() {

for (String myTm : tm) {
    tc.send(myTm);
} 

}

How can I mock tm in my testcase? Notice I also use the value in my send method.

br,

//mike
Message has been deleted

Marcin Grzejszczak

unread,
Aug 22, 2013, 1:40:24 AM8/22/13
to moc...@googlegroups.com
Oh Now I can see what the problem is... You should not create the list by using new but have a for instance some sort of factory that will provide you with the list. Then you can stub the method to get your list.

mikaelpe...@gmail.com

unread,
Aug 22, 2013, 2:10:05 AM8/22/13
to moc...@googlegroups.com
Hi,

Thanks for input. Also do you know how to use a real list for the iterator:


for (String myTm : tm) {
    tc.send(myTm);
} 

I tried to find anything about this but I cannot see any example on how to use the suggest asList().

br,

//mike

Marcin Grzejszczak

unread,
Aug 22, 2013, 2:16:15 AM8/22/13
to moc...@googlegroups.com
If you are able to provide a mocked list then in order for the enhanced loop to work you have to stub the hasNext() and next() methods.


        List<String> listMock = mock(List.class);

        Iterator<String> stringIterator = mock(Iterator.class);

        when(listMock.iterator()).thenReturn(stringIterator);

        when(stringIterator.hasNext()).thenReturn(true, true, true, false);

        when(stringIterator.next()).thenReturn("a","b","c");


In this way you provide that there are three elements "a","b" and "c" and the fourth hasNext() call returns false.

mikaelpe...@gmail.com

unread,
Aug 22, 2013, 2:27:24 AM8/22/13
to moc...@googlegroups.com
Hi,

Yes this is the way to do it and I have also read that you should not mock iterators. Don't really understand why:

https://groups.google.com/forum/#!searchin/mockito/mock$20iterator/mockito/5OMDAyci5TY/EbXOBxXep0IJ

and how it will be implemented in my example. I know it is not needed but I am curious so If anyone knows ....

br,

//mike

Marcin Grzejszczak

unread,
Aug 22, 2013, 2:48:46 AM8/22/13
to moc...@googlegroups.com
I have totally forgotten about such approach and it is really cool :) 

The asList function gives you the oportunity to initialize a real list with the elements provided as vararg argument of the asList function. In this way what actually happens is that you have all the stubbing of the iterator and hasNext for free and done for you. 

So in your case if you had this factory interface mocked that would provide you with the list you would just have to make it return your asList("a","b","c"). It's a one liner so it's more convienient then creating a new ArrayList and filling it up with elements.

mikaelpe...@gmail.com

unread,
Aug 22, 2013, 3:50:51 AM8/22/13
to moc...@googlegroups.com
I tried to implement it:

Here is test class:

import java.util.Arrays;
import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(TestIterator.class)
public class IteratorTest {


    TestIterator classUnderTest;
    List<String> ids;


    @Before
    public void setup() {
        ids = Arrays.asList("a", "b");
        classUnderTest = new TestIterator();
    }

    @Test
    public void test() {

        PowerMockito.mockStatic(TestIterator.class);
        Mockito.when(TestIterator.createTm()).thenReturn(ids);
        classUnderTest.setState();
        PowerMockito.verifyStatic(Mockito.times(1));

    }


}

This is my class under test:

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


public class TestIterator {

    static List<String> tm = TestIterator.createTm();


    
public void setState() {


    for (String myTm :
 tm) {
        System.out.println("Sending "+myTm);
    }

    }

    public static List<String> createTm() {
        return new ArrayList<String>();
    }
}



But I don't see that the iterator is working. Anyone that knows what I am missing?

br,

//mike

Marcin Grzejszczak

unread,
Aug 22, 2013, 3:59:17 AM8/22/13
to moc...@googlegroups.com
That's all wrong man :P

Could you please tell me what are you actually trying to test and why your implementation looks like this? I mean you have some static methods, you are using PowerMockito for such a simple scenario etc.

In your case you should have a separate Interface and its implementation that would provide you with the list. What is more you should inject it via a constructor or a setter.

I don't think that this discussion should be continued here - let's post the final solution here after we come to terms how to write the test ok?

You can send me a msg directly to me at marcin.grzejszczak(at)gmail.com - I'll explain it to you.

--
You received this message because you are subscribed to the Google Groups "mockito" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mockito+u...@googlegroups.com.
To post to this group, send email to moc...@googlegroups.com.
Visit this group at http://groups.google.com/group/mockito.
For more options, visit https://groups.google.com/groups/opt_out.

David Wallace

unread,
Aug 22, 2013, 5:59:40 AM8/22/13
to moc...@googlegroups.com
Please don't mock the list or stub the iterator methods.  A list is a value object.  If you have a way of injecting a mock, then you can equally well inject a real list.  So just make a real list with the values that you need, and use that.  It will be far more readable and far easier to maintain.

mikael petterson

unread,
Aug 22, 2013, 6:50:30 AM8/22/13
to moc...@googlegroups.com
Hi,

I agree with you.

I rewrote my class and used injection like:
public class TestIterator {

    public TmInterface tm;


    public TestIterator(TmInterface tm) {
        this.tm = tm;
    }
  

    public void setState() {
   
        for (String myTm : tm.getTm()) {
            System.out.println("Sending " + myTm);
    }

    }

   
  
}


br,

//mike

mikael petterson

unread,
Aug 22, 2013, 6:55:18 AM8/22/13
to moc...@googlegroups.com
I thought I would publish one possible solution ( after help from Marcin) to the problem ( don't care about bad naming ).

br,

//mike

My class to test:
public class TestIterator {

    public TmInterface tm;


    public TestIterator(TmInterface tm) {
        this.tm
 = tm;
    }
  

    public void setState() {
   
        for (String myTm : tm.getTm()) {
            System.out.println("Sending " + myTm);
    }

    }

   
  
}
Refactored out:

Interface:

import java.util.List;

public interface TmInterface {

    public List<String> getTm();

}


Implementation:
import java.util.ArrayList;
import java.util.List;

public class TmImpl implements TmInterface {
    
    
    public TmImpl(){

    }
    @Override
    public List<String> getTm() {
        
List<String> tm = new ArrayList<String>
();
        tm.add("001000");
        tm.add("002000");
        return tm;
    }

}

And my test class now becomes very simple:

import java.util.Arrays;
import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;


public class IteratorTest {


    TestIterator classUnderTest;
    TmInterface tmClass;
    
List<String> ids;


    @Before
    public void
 setup() {
        tmClass = Mockito.mock(TmInterface.class);
        ids = Arrays.asList("a", "b");
        classUnderTest = new TestIterator(tmClass);

    }


    @Test
    public void test() {
        Mockito.when(tmClass.getTm()).thenReturn(ids);
        classUnderTest.setState();


    }


}

Reply all
Reply to author
Forward
0 new messages