当我们需要模拟重载的方法之一(其中之一使用varargs)时,很难使用Mockito。考虑Spring的RestTemplate
void put(String url, Object request, Object... uriVariables) throws RestClientException;
void put(String url, Object request, Map<String, ?> uriVariables) throws RestClientException;
直接模拟第二个方法是可行的,但是模拟第一个方法是不可能的,因为使用any()
会导致模棱两可的方法调用与这两个方法匹配,并且没有其他方法可以匹配Object...
分享我为解决问题而提出的解决方案,以帮助同船上的那些人。欢迎其他所有选择。
答案 0 :(得分:1)
可以通过使用功能为模拟提供defaultAnswer
来解决此问题。 defaultAnswer将评估该调用是针对特定方法的,并执行所需的操作,如果所需的方法未定位,则让调用遵循自然流程。
这可以用一个例子很好地解释。考虑下面的类中的两个重载方法:
public class StringConcat {
public String concatenate(int i, String... strings) {
return i + Arrays.stream(strings).collect(Collectors.joining(","));
}
public String concatenate(int i, List<String> strings) {
return i + strings.stream().collect(Collectors.joining(","));
}
}
可以使用Mockito模拟第二种方法,如下所示:
StringConcat stringConcat = mock(StringConcat.class);
when(stringConcat.concatenate(anyInt(), anyList())).thenReturn("hardcoded value");
要表示varargs,我们没有anyVararg()
方法(不建议使用,并且不起作用,不确定它是否在较早版本中可用)。但是可以通过使用defaultAnswer创建模拟来处理相同的问题,如下所示:
@Test
void testWithDefaultAnswer(){
// Creating mock object with default answer
StringConcat stringConcat = mock(StringConcat.class, invocation -> {
Method method = invocation.getMethod();
if (method.getName().contains("concatenate") &&
method.getParameters()[method.getParameters().length-1].isVarArgs()){
if(invocation.getArguments().length>=method.getParameterCount()){
List varArgParams = Arrays.stream(invocation.getArguments())
.skip(method.getParameterCount()-1)
.collect(Collectors.toList());
return invocation.getArguments()[0]+":"
+varArgParams.toString(); // mocked result when varargs provided
}
return ""+invocation.getArguments()[0]; // mocked result when varargs not provided
}
return Answers.RETURNS_DEFAULTS.answer(invocation); // Ensures seamless mocking of any other methods
});
// Mock any non varargs methods as needed
when(stringConcat.concatenate(anyInt(), anyList())).thenReturn("hardcoded"); // mocking as usual
// Test the mocks
System.out.println(stringConcat.concatenate(1, "a", "b")); // default answer based mock, with varargs provided
System.out.println(stringConcat.concatenate(1)); // default answer based mock, without varargs provided
System.out.println(stringConcat.concatenate(1, Lists.newArrayList("a", "b"))); // mocked non varargs method
}
输出:
1:[a, b]
1
hardcoded