手写简单版的powermock,写着玩

手写简单版的powermock,写着玩,第1张

因为觉得powermock的运用cglib来修改字节码挺好玩的,所以这几天自己研究了下,还是那样,基于TDD来编写powermock,写这篇文章的目的是为了厘清自己的思路

首先powermock的核心就是when和thenReturn这俩东西,when的时候,其实就是打了个桩:

public static  OngoingStubbing when(T methodCall) {
        //return Mockito.when(methodCall);
        return new OngoingStubbing(methodCall);
    }

这个桩子OngoingStubbing,在thenReturn时也会用到:

public class OngoingStubbing {


    //answer
    // add ans
    // add return
    //
    private final InvocationContainerImpl0 invocationContainerImpl = new InvocationContainerImpl0();


    private T method;

    public OngoingStubbing (T method) {
        this.method = method;
    }
    public OngoingStubbing thenReturn(T var1) {
        invocationContainerImpl.addAnswer(new Return0(var1));
        return this;
    }
}

可以看到里面有个invocationContainerImpl,这个变量是用来干什么的呢? 其实就是为了处理thenReturn时的返回变量的,通过addAnswer方法,既然是这样,那么这些answer是在什么时候取出来的呢? 当然是在后面实际调用方法时,会取到这个Answer,所以是怎么取到的?

也是通过invocationContainerImpl的方法findAnswersForStubbing,那么findAnswersForStubbing是在什么时候被调用的呢,就是通过修改字节码来使他在callback时会被调用到,callback的实现,在powermock分为七种,我们在这里用的MethodInteceptor,一个简单的实现是:

package mockito;

import org.mockito.cglib.proxy.MethodInterceptor;
import org.mockito.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class MethodInterceptorImpl implements MethodInterceptor {

    public Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable {
        return "2";
    }
}

自己写的MockCreator用来使用这个字节码增强:

package mockito;

import org.mockito.cglib.proxy.Enhancer;

public class MockCreator {

    public static  T createMock(Class type) {

        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(type);
        // 设置回调方法 - 回调方法实现为 FixedValue (固定值) .
        enhancer.setCallback(new MethodInterceptorImpl());
        // 创建 SampleClass 的代理子类实例
        T proxy = (T) enhancer.create();
        return proxy;
    }
}

现在的一个比较简略的实现就是,我们在测试方法运行之前,把需要mock的东西mock住:

import mockito.MethodInterceptorImpl;
import mockito.PowerMockito;
import mockito.StaticClass;
import org.junit.Before;
import org.junit.Test;
import org.mockito.cglib.proxy.Enhancer;
import org.mockito.cglib.proxy.FixedValue;

import static mockito.MockCreator.createMock;
import static mockito.PowerMockito.*;
public class MockTest {


    StaticClass staticmethod;

    //把stati to mock method
    // return 时把
    //nongq inte zuolesha
    @Before
    public void setUp() throws Exception{
        staticmethod = createMock(StaticClass.class);
    }



    @Test
    public void test() {

        mockStatic(StaticClass.class);
        StaticClass sc = new StaticClass();
        when(sc.nmsl()).thenReturn("2");
        System.out.println(staticmethod.nmsl());
    }


}

但是这样的一个没有实现的点,就是thenReturn时的value没法传进MethodImpl去,所以现在最难的一步就是,如何把thenReturn("2")的"2"传进callback里面

扩展callbackilter,可以用来多次增强并且在指定环境使用指定的方法,可参考:

实战CGLib系列之proxy篇(二):回调过滤CallbackFilter_java风云的博客-CSDN博客

我们看powermock源码的话,其实thenReturn就是addAnswer,

public OngoingStubbing thenReturn(T var1) {
        invocationContainerImpl.addAnswer(new Return0(var1));
        return this;
    }

所以其实就是我们要把invocationImpl传进MethodInteceptorImpl里面,那么powermock是通过mockHandlerImpl处理的:

现在就是不知道invocationImpl是啥时候传进去mockHandlerImpl的

应该是when的时候,我们会把invocationImpl注册进mockHandler里面,不是,when的时候会生成一个ongoingstub,然后这个stub给后面使用

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/877001.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)

保存