Mockito doesn't correctly stub methods taking list as argument
Asked Answered
D

3

6

I am trying to mock a class and return a stubbed list of objects when a method on the mocked object is called. Lets consider following code :

interface MyRepositry{
       public List<MyClass> getMyClassInstances(String str,Long id,List<Integer> statusList);
}

I am mocking above method ivocation as follows :

when(myRepository.getMyClassInstances("1234", 200L, stubbedList)).thenReturn(stubbedMyClassInstanceList);

where

 stubbedList 

is the list I create by inserting two integers 1 and 3. In real call also I pass the list I construct which has integers 1 and 3. Point ot note here is stubbedList object and the list object in real call are different but always contain two integers 1 and 3.

stubbedMyClassInstanceList    

is the stubbed list of MyClass instances.

However mockito return an empty list when i run the test. I did some debugging and I guess mockito is not able to match the list object that I am using in

      when(..).thenReturn(..)

call and in actual call and hence doesn't find the correct signature.

I cannot use

anyList() 

matcher as I always pass list of two integers (1 and 3).

I have resolved the problem by using custom

     ArgumentMatcher 

as follows :

     class StatusMatcher extends ArgumentMatcher<List> {
    public boolean matches(Object list) {
        List statuses = ((List) list);
        return (statuses.size() == 2 && statuses.contains(1) && statuses.contains(3));
    }
}

So the question is :

1) Is my guess about why the stubbing/mocking not working correct? 2) and is the solution I have used correct?

Deflect answered 28/10, 2015 at 14:21 Comment(2)
Please provide a full (but simple) working example that demonstrate the problem.Backhouse
i cannot provide actual code as it is licenced to company i am working for. However I have given minimal relavent code . I can explain more if you don't find any of the above code explanatory enough.Deflect
S
8

Mockito naturally uses equals() for argument matching. The equals() method in List<T> specifies that two lists are defined to be equal if they contain the same elements in the same order.

Your custom argument matcher, that you say works, is not considering order.

So maybe the 1 and 3 are in the wrong order in the List<T>?

Scatterbrain answered 28/10, 2015 at 14:34 Comment(5)
Or the List are different types.Backhouse
My custom matcher does not check order it just checks it contains the right elements or notDeflect
List are of same types i.e. Arraylist of Integer objectsDeflect
I will check the order thoughDeflect
Solutions for verifying that method was called with a list, ignoring order of elements in the list, can be found here.Constable
E
0

Mockito has an eq() method

You could try:

import static org.mockito.Matchers.eq;

.....

when(myRepository.getMyClassInstances(eq("1234"), eq(200L), eq(stubbedList)).thenReturn(stubbedMyClassInstanceList);
Endow answered 28/10, 2015 at 14:34 Comment(0)
C
0

You can check equality by yourself if your list consists of distinct elements:

    Mockito.when(myRepository.getMyClassInstances("1234", 200L, Mockito.anyList())).thenAnswer(new Answer<List<MyClass>>() {
        @Override
        public List<MyClass> answer(InvocationOnMock invocation) throws Throwable {
            Set<MyClass> argSet = invocation.getArgument(2).stream().collect(Collectors.toSet());
            Set<MyClass> stubbedSet = stubbedList.stream().collect(Collectors.toSet());
            if (argSet.equals(stubbedSet)) {
                return stubbedMyClassInstanceList;
            }else {
                return myRepository.getMyClassInstances("1234", 200L, invocation.getArgument(2));
            }
        }
    });
Circus answered 14/6, 2022 at 5:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.