Create a mocked list by mockito

169,734

Solution 1

OK, this is a bad thing to be doing. Don't mock a list; instead, mock the individual objects inside the list. See Mockito: mocking an arraylist that will be looped in a for loop for how to do this.

Also, why are you using PowerMock? You don't seem to be doing anything that requires PowerMock.

But the real cause of your problem is that you are using when on two different objects, before you complete the stubbing. When you call when, and provide the method call that you are trying to stub, then the very next thing you do in either Mockito OR PowerMock is to specify what happens when that method is called - that is, to do the thenReturn part. Each call to when must be followed by one and only one call to thenReturn, before you do any more calls to when. You made two calls to when without calling thenReturn - that's your error.

Solution 2

When dealing with mocking lists and iterating them, I always use something like:

@Spy
private List<Object> parts = new ArrayList<>();

Solution 3

We can mock list properly for foreach loop. Please find below code snippet and explanation.

This is my actual class method where I want to create test case by mocking list. this.nameList is a list object.

public void setOptions(){
    // ....
    for (String str : this.nameList) {
        str = "-"+str;
    }
    // ....
}

The foreach loop internally works on iterator, so here we crated mock of iterator. Mockito framework has facility to return pair of values on particular method call by using Mockito.when().thenReturn(), i.e. on hasNext() we pass 1st true and on second call false, so that our loop will continue only two times. On next() we just return actual return value.

@Test
public void testSetOptions(){
    // ...
    Iterator<SampleFilter> itr = Mockito.mock(Iterator.class);
    Mockito.when(itr.hasNext()).thenReturn(true, false);
    Mockito.when(itr.next()).thenReturn(Mockito.any(String.class);  

    List mockNameList = Mockito.mock(List.class);
    Mockito.when(mockNameList.iterator()).thenReturn(itr);
    // ...
}

In this way we can avoid sending actual list to test by using mock of list.

Share:
169,734
Tien Nguyen
Author by

Tien Nguyen

I have been on the software adventure since 2011. I love to learn and share knowledge to stackoverflow network. Email: [email protected]

Updated on April 08, 2020

Comments

  • Tien Nguyen
    Tien Nguyen about 4 years

    I want to create a mocked list to test below code:

     for (String history : list) {
            //code here
        }
    

    Here is my implementation:

    public static List<String> createList(List<String> mockedList) {
    
        List<String> list = mock(List.class);
        Iterator<String> iterHistory = mock(Iterator.class);
    
        OngoingStubbing<Boolean> osBoolean = when(iterHistory.hasNext());
        OngoingStubbing<String> osHistory = when(iterHistory.next());
    
        for (String history : mockedList) {
    
            osBoolean = osBoolean.thenReturn(true);
            osHistory = osHistory.thenReturn(history);
        }
        osBoolean = osBoolean.thenReturn(false);
    
        when(list.iterator()).thenReturn(iterHistory);
    
        return list;
    }
    

    But when the test run it throw exception at line:

    OngoingStubbing<DyActionHistory> osHistory = when(iterHistory.next());
    

    for details:

    org.mockito.exceptions.misusing.UnfinishedStubbingException: 
    Unfinished stubbing detected here:
    -> at org.powermock.api.mockito.PowerMockito.when(PowerMockito.java:495)
    
    E.g. thenReturn() may be missing.
    Examples of correct stubbing:
        when(mock.isOk()).thenReturn(true);
        when(mock.isOk()).thenThrow(exception);
        doThrow(exception).when(mock).someVoidMethod();
    Hints:
     1. missing thenReturn()
     2. you are trying to stub a final method, you naughty developer!
    

    How can i fix it ? Thanks

  • BlueShark
    BlueShark over 9 years
    but if you REALLY had to, how would you mock a list?
  • Dawood ibn Kareem
    Dawood ibn Kareem over 9 years
    Why would you REALLY have to? It's invariably the wrong thing to be doing. This is like asking "what if you REALLY had to use a hammer to drive a screw". It's the wrong approach - the wrong tool for the job.
  • BlueShark
    BlueShark over 9 years
    how do you return a normal list then with mocked items inside?
  • Dawood ibn Kareem
    Dawood ibn Kareem over 9 years
    Look at my answer to the question that I linked to.
  • GabrielOshiro
    GabrielOshiro over 5 years
    Question: How do I solve X? Answer: Don't do X, do Y instead. I don't get why this is the accepted answer.
  • Dawood ibn Kareem
    Dawood ibn Kareem over 5 years
    @GabrielOshiro - I'll try to help you understand. The OP posted some code with an error in it, and asked the question "how can I fix it". My third paragraph explained their error. My answer offered a solution to their problem. So I've actually answered their question completely. I hope this helps you "get why" this is the accepted answer.
  • ahmednabil88
    ahmednabil88 over 3 years
    Summary: Don't mock a list; instead, mock the individual objects inside the list