美文网首页
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