1 错误场景
在mock变参方法sum时候,增加一条打印语句,然后调用旧方法,抛出参数类型不匹配异常
import mockit.Invocation;
import mockit.Mock;
import mockit.MockUp;
import org.testng.annotations.Test;
import java.util.Arrays;
public class App {
@Test
public void testSum() {
// new MockUp<Method>(Method.class) {
// @Mock
// public boolean isVarArgs() {
// return false;
// }
// };
new MockUp<Base>(Base.class) {
@Mock
public int sum(Invocation invocation, int first, int... args) {
System.out.println("mock sum method");
return invocation.proceed(first, args);
}
};
Base base = new Base();
int result = base.sum(10, 1, 2, 3, 4, 5);
System.out.println(result);
}
}
class Base {
int sum(int first, int... nums) {
return first + Arrays.stream(nums).sum();
}
}
运行结果如下:
mock sum method
java.lang.IllegalArgumentException: Failure to invoke method: int Base.sum(int,int[])
at App$1.sum(App.java:22)
at Base.sum(App.java)
at App.testSum(App.java:27)
Caused by: java.lang.IllegalArgumentException: argument type mismatch
... 3 more
2 debug调试
在invocation.proceed(first, args)
所在行打上断点,开始debug
args形参以数组形式传入int[5] {1, 2, 3, 4, 5}
,这个问题不大
然后看Invovation
的proceed
方法,同样采用变参的方式
@Nullable
public final <T> T proceed(@Nullable Object... replacementArguments) {
return ((BaseInvocation)this).doProceed(replacementArguments);
}
最后跟进doProceed
方法,类似于动态代理,
@Nullable
public final <T> T doProceed(@Nullable Object[] replacementArguments) {
Member memberToInvoke = this.getRealMember();
if (memberToInvoke instanceof Constructor) {
this.prepareToProceed();
return null;
} else {
this.prepareToProceed();
Method realMethod = (Method)memberToInvoke;
Object[] actualArgs = this.getInvokedArguments();
// 如果方法包含变参,则通过createArgumentsArrayWithVarargs方法将所有参数封装到数组中
// 然而参数在传入时,就已经封装成数组了,再次封装导致变参最后变成二维数组,于是invoke调用时抛出类型不匹配异常
if (replacementArguments != null && replacementArguments.length > 0) {
actualArgs = realMethod.isVarArgs() ? createArgumentsArrayWithVarargs(actualArgs.length, replacementArguments) : replacementArguments;
}
Object var5;
try {
var5 = MethodReflection.invoke(this.getInvokedInstance(), realMethod, actualArgs);
} finally {
this.cleanUpAfterProceed();
}
return var5;
}
}
image.png
3 规避方法
既然参数的处理由Method.isVarArgs
决定,便直接将其mock成false
new MockUp<Method>(Method.class) {
@Mock
public boolean isVarArgs() {
return false;
}
};
网友评论