Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mockito returnsFirstArg() doesn't work with generic first arg

EDIT: I've finally created an issue on mockito github project.

I'm trying to mock the typed method getNameElement of Interface RoomGeneralService to return the first arg, using Mockito AdditionalAnswers.returnsFirstArg functionality:

Interface to mock:

interface PrimaryKeyElement<T> {
   public String getNameElement(T primaryKey);
}

interface RoomGeneralService extends PrimaryKeyElement<String> {
   // ...
}

My test (note the imports)

import static org.mockito.AdditionalAnswers.returnsFirstArg;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.when;

@RunWith(PowerMockRunner.class)
public class SampleTest {

   @Mock
   RoomGeneralService roomGeneralService;

   @Test
   public void testFoo() throws Exception {
      when(roomGeneralService.getNameElement(anyString())).thenAnswer(returnsFirstArg());
      //...
   }
}

Also I've tried with other combinations, but without success so far:

when(roomGeneralService.getNameElement(Matchers.<String>any())).thenAnswer(returnsFirstArg());
doAnswer(returnsFirstArg()).when(roomGeneralService.getNameElement(anyString()));
doReturn(returnsFirstArg()).when(roomGeneralService.getNameElement(anyString()));

Error received:

The reason for this error can be : 1. The wanted argument position is incorrect. 2. The answer is used on the wrong interaction.

Position of the wanted argument is 0 and the possible argument indexes for this method are : [0] Object

Workaround:

I know I can create my own answer, and in fact it's working fine if instead of use returnFirstArg() I do something like this:

when(roomGeneralService.getNameElement(anyString())).thenAnswer(new Answer<String>() {
   @Override
   public String answer(InvocationOnMock invocation) throws Throwable {
      return (String) invocation.getArguments()[0];
   }
});

But I would use returnFirstArg() as in the rest of my tests (tests look cleaner), as well as mocking is working fine if the method getNameElement would receive an String instead a T arg.

Thanks for the help.

like image 789
troig Avatar asked Nov 09 '22 12:11

troig


1 Answers

It seems Mockito isn't smart enough to deduce that the parameter type will be bound to String in the parameterized subinterface.

You can override the method in the subinterface

interface RoomGeneralService extends PrimaryKeyElement<String> {
    @Override
    public String getNameElement(String primaryKey);
}

Mockito won't have to guess. It will clearly see String as the parameter type of the stubbed method.

like image 191
Sotirios Delimanolis Avatar answered Nov 14 '22 22:11

Sotirios Delimanolis