Mockito:将答案附加到任意对象实例的每个方法
Mockito: Attach Answer to every method of arbitrary Object instance
我有以下情况:
我想将 Answer
附加到特定 class 实例的每个方法调用。例如 class
public class Example {
public int example1() { /* */ }
public int example2(Object a) { /* */ }
public int example3(Object a, Integer b) { /* */ }
public int example4(int a) { /* */ }
}
我想做以下事情
public Example attachToExample(Example ex) {
Example spy = Mockito.spy(ex);
Answer<Object> answer = /* */;
doAnswer(answer).when(spy).example1();
doAnswer(answer).when(spy).example2(any());
doAnswer(answer).when(spy).example3(any(), any());
doAnswer(answer).when(spy).example4(anyInt());
return spy;
}
这行得通,但我想做的是将其推广到不仅 Example
个实例,而且推广到任意对象。
所以我想做的是
public Object attachToExample(Object o) {
Object spy = Mockito.spy(o);
Answer<Object> answer = /* */;
for(Method m : o.getClass().getMethods()) {
/* skipping methods that cannot be mocked (equals/hashCode/final/..) */
doAnswer(answer).when(spy)./* Method m with according arguments */;
}
return spy;
}
我需要做的是构造参数匹配器 any
/anyInt
/.. 取决于每个方法的参数数量及其类型(primitive/non 原语).理想情况下,我会创建一个这样的参数列表:
Class<?>[] params = m.getParameterTypes();
ArrayList<Object> args = new ArrayList<>();
for (Class<?> param : params) {
if ("int".equals(param.toString())) {
args.add(ArgumentMatchers.anyInt());
} else { // Cases for other primitive types left out.
args.add(ArgumentMatchers.any()); // Found non primitive. We can use 'any()'
}
}
try {
doAnswer(answer).when(spy).getClass().getMethod(m.getName(), m.getParameterTypes())
.invoke(spy, args.toArray());
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
这不起作用,因为不支持在存根之外使用参数匹配器,但我希望这能说明我想做什么。
是否有任何方法可以完成这项工作,或者是否有不同的方法来存档我想做的事情?
好的,我找到了一种方法来做我想做的事:
虽然参数数组不能在 invoke
调用之前构建,但我们可以通过外部方法调用来实现,如下所示:
try {
doAnswer(answer).when(spy).getClass().getMethod(m.getName(), m.getParameterTypes())
.invoke(spy, constructArguments(m));
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
其中 constructArguments
如下:
private static Object[] getArgumentMatcher(Method m) {
Class<?>[] types = m.getParameterTypes();
Object[] res = new Object[types.length];
for(int i = 0; i < types.length; ++i) {
if (types[i].isPrimitive()) {
// For primitives we need to specify the type explicitly ¯\_(ツ)_/¯
res[i] = any(types[i]);
} else {
res[i] = any();
}
}
return res;
}
我有以下情况:
我想将 Answer
附加到特定 class 实例的每个方法调用。例如 class
public class Example {
public int example1() { /* */ }
public int example2(Object a) { /* */ }
public int example3(Object a, Integer b) { /* */ }
public int example4(int a) { /* */ }
}
我想做以下事情
public Example attachToExample(Example ex) {
Example spy = Mockito.spy(ex);
Answer<Object> answer = /* */;
doAnswer(answer).when(spy).example1();
doAnswer(answer).when(spy).example2(any());
doAnswer(answer).when(spy).example3(any(), any());
doAnswer(answer).when(spy).example4(anyInt());
return spy;
}
这行得通,但我想做的是将其推广到不仅 Example
个实例,而且推广到任意对象。
所以我想做的是
public Object attachToExample(Object o) {
Object spy = Mockito.spy(o);
Answer<Object> answer = /* */;
for(Method m : o.getClass().getMethods()) {
/* skipping methods that cannot be mocked (equals/hashCode/final/..) */
doAnswer(answer).when(spy)./* Method m with according arguments */;
}
return spy;
}
我需要做的是构造参数匹配器 any
/anyInt
/.. 取决于每个方法的参数数量及其类型(primitive/non 原语).理想情况下,我会创建一个这样的参数列表:
Class<?>[] params = m.getParameterTypes();
ArrayList<Object> args = new ArrayList<>();
for (Class<?> param : params) {
if ("int".equals(param.toString())) {
args.add(ArgumentMatchers.anyInt());
} else { // Cases for other primitive types left out.
args.add(ArgumentMatchers.any()); // Found non primitive. We can use 'any()'
}
}
try {
doAnswer(answer).when(spy).getClass().getMethod(m.getName(), m.getParameterTypes())
.invoke(spy, args.toArray());
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
这不起作用,因为不支持在存根之外使用参数匹配器,但我希望这能说明我想做什么。
是否有任何方法可以完成这项工作,或者是否有不同的方法来存档我想做的事情?
好的,我找到了一种方法来做我想做的事:
虽然参数数组不能在 invoke
调用之前构建,但我们可以通过外部方法调用来实现,如下所示:
try {
doAnswer(answer).when(spy).getClass().getMethod(m.getName(), m.getParameterTypes())
.invoke(spy, constructArguments(m));
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
其中 constructArguments
如下:
private static Object[] getArgumentMatcher(Method m) {
Class<?>[] types = m.getParameterTypes();
Object[] res = new Object[types.length];
for(int i = 0; i < types.length; ++i) {
if (types[i].isPrimitive()) {
// For primitives we need to specify the type explicitly ¯\_(ツ)_/¯
res[i] = any(types[i]);
} else {
res[i] = any();
}
}
return res;
}