5.当存根被覆盖时

  • 本文关键字:覆盖 存根 java mockito
  • 更新时间 :
  • 英文 :


我试图按如下方式存根我的mock,

when(someMock.someMethod(Matchers.<SomeInterface<MyType>> any()).thenReturn(someValue);

,

when(someMock.someMethod(Matchers.<SomeInterface<Map<String,Boolean>>> any()).thenReturn(someOtherValue);

我注意到第二个存根覆盖了第一个。所以即使调用someMock.someMethod(new SomeInterfaceImplementation());

也能得到someOtherValue

我不知道这里少了什么。我试着在Mockito文档中寻找这个特定的用例,但我没有找到任何东西。

由于类型擦除,Mockito将无法在运行时确定传递给someMock.someMethodSomeInterface<T>实例的通用参数。任何对someMethod的调用都将显示为使用没有泛型参数的SomeInterface实例。

JavaDoc for Matchers用一个警告暗示了这个问题(尽管它没有解释原因):

any族方法不做任何类型检查,这些只是为了避免在代码中强制转换。如果要执行类型检查,请使用isA(Class)方法。然而,在未来的主要版本中,这可能会改变(可以添加类型检查)。

还有其他一些辅助方法,如anyListOf,它们似乎处理集合的泛型参数,但这些方法只是为了方便而存在,实际上并不会检查泛型类型:

anyList()的通用友好别名。它是@SuppressWarnings("unchecked")的替代方法,可以保持代码中没有编译器警告。

任意列表或null

这个方法不做任何类型检查,它只是在你的代码中避免强制类型转换。然而,在未来的主要版本中,这可能会改变(可以添加类型检查)。

因为any()匹配器将匹配任何对象,而不考虑类型和泛型参数,所以第二次使用any()调用when()将覆盖第一次调用。这个问题的唯一解决方案是对两种类型的调用只调用when(...)一次,并进行某种运行时检查以确定结果应该是什么(例如,在传递给thenAnswerAnswer中)。

例如,假设我们想模拟下面的类(实际上不值得模拟,但请原谅我):

public class SomeClass {
    public <T> T getFirst(List<T> list) {
        return list.get(0);
    }
}

getFirst方法与您的类有相同的问题,因为使用any/isA/anyList/anyListOf匹配器将无法区分List<String>List<Integer>

这里有一种方法来模拟andAnswer:

@Test
public void testGetFirst() {
    SomeClass mock = mock(SomeClass.class);
    
    when(mock.getFirst(Matchers.<List<?>>any())).thenAnswer(new Answer<Object>() {
        @Override
        public Object answer(InvocationOnMock invocation) {
            List<?> list = (List<?>) invocation.getArguments()[0];
            // Inspect the contents of the list to know which type to return
            Object first = list.get(0);
            if (first instanceof String) {
                return "Z";
            } else if (first instanceof Integer) {
                return 1000;
            } else {
                return null;
            }
        }
    });
    
    String firstString = mock.getFirst(Arrays.asList("A", "B", "C"));
    System.out.println(firstString); // prints Z
    
    Integer firstInteger = mock.getFirst(Arrays.asList(1, 2, 3));
    System.out.println(firstInteger); // prints 1000
}

这很难看,而且可能很难实现,这取决于您实际使用泛型类型的方式,但我相信这是解决运行时缺乏泛型类型信息的唯一方法。

相关内容

  • 没有找到相关文章

最新更新