Mockito returnsFirstArg() 不适用于通用的第一个参数

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

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

我正在尝试使用 Mockito AdditionalAnswers.returnsFirstArg 功能将接口 RoomGeneralService 的类型化方法 getNameElement 模拟为 return 第一个参数:

模拟接口:

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

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

我的测试(注意进口)

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());
      //...
   }
}

我也尝试过其他组合,但到目前为止没有成功:

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

收到错误:

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

解决方法

我知道我可以创建自己的答案,事实上,如果不使用 returnFirstArg() 我会这样做,它工作正常:

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

但我会像在我的其余测试中一样使用 returnFirstArg()(测试看起来更干净),并且如果方法 getNameElement 会收到 String,模拟工作正常取而代之的是 T arg.

感谢您的帮助。

Mockito 似乎不够聪明,无法推断参数类型将绑定到参数化子接口中的 String

您可以覆盖子接口中的方法

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

Mockito 无需猜测。它会清楚地看到 String 作为存根方法的参数类型。

终于决定开issue了(#1071) on mockito github project and it has been fixed in version 2.8.29 (See the official changelog)感谢Mockito团队这么快就解决了!

引用@ChristianSchwarz,这里有一个问题解释:

Mockito checks if the argument type is compatible with the return type to make a misuse ot the API as soon as posible visible. In this case the argument-type Object is inferred from the generic type T, due to type erasure. Since Object is not a subtype of String Mockito throws the exception you see.

Solution: The issue can by fixed by inferring the argument-type of the actual argument-instance. In case the argument-type is a primitive or the arg is null Mockito must fallback and use the type provided by method signature.