美文网首页
Jmockit 可变参数方法报argument type mis

Jmockit 可变参数方法报argument type mis

作者: halfempty | 来源:发表于2018-11-08 11:51 被阅读0次

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},这个问题不大

然后看Invovationproceed方法,同样采用变参的方式

@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;
    }
};

相关文章

网友评论

      本文标题:Jmockit 可变参数方法报argument type mis

      本文链接:https://www.haomeiwen.com/subject/yugixqtx.html