因为觉得powermock的运用cglib来修改字节码挺好玩的,所以这几天自己研究了下,还是那样,基于TDD来编写powermock,写这篇文章的目的是为了厘清自己的思路
首先powermock的核心就是when和thenReturn这俩东西,when的时候,其实就是打了个桩:
public static <T> OngoingStubbing<T> when(T methodCall) {
//return Mockito.when(methodCall);
return new OngoingStubbing<T>(methodCall);
}
这个桩子OngoingStubbing,在thenReturn时也会用到:
public class OngoingStubbing<T> {
//answer
// add ans
// add return
//
private final InvocationContainerImpl0 invocationContainerImpl = new InvocationContainerImpl0();
private T method;
public OngoingStubbing (T method) {
this.method = method;
}
public OngoingStubbing<T> 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> T createMock(Class<T> 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<T> thenReturn(T var1) {
invocationContainerImpl.addAnswer(new Return0(var1));
return this;
}
所以其实就是我们要把invocationImpl传进MethodInteceptorImpl里面,那么powermock是通过mockHandlerImpl处理的:
现在就是不知道invocationImpl是啥时候传进去mockHandlerImpl的
应该是when的时候,我们会把invocationImpl注册进mockHandler里面,不是,when的时候会生成一个ongoingstub,然后这个stub给后面使用
|