为了节省时间,找了一个早期的版本来理解Mockito的运行机制。
---示例代码如下:
package test;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.junit.Test;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
public class Test1 {
public static void main(String[] args) {
Obj mock = mock(Obj.class);
System.out.println(mock.getClass());
when(mock.test()).thenReturn(200);
System.out.println(mock.test());
assertEquals("预期返回1", 200, mock.test());
HttpServletRequest request = mock(HttpServletRequest.class);
when(request.getParameter("foo")).thenReturn("boo111");
when(request.getParameter("foo")).thenReturn("boo111222");
System.out.println(request.getParameter("foo"));
}
}
首先是生成代理类实例,基于cglib来
public <T> T imposterise(final MethodInterceptor interceptor, Class<T> mockedType, Class<?>... ancilliaryTypes) {
// 看到这里了
try {
//设置构造函数可访问
setConstructorsAccessible(mockedType, true);
// 基于第三方的包构造代理类
Class<?> proxyClass = createProxyClass(mockedType);
// 构造代理实例
return mockedType.cast(createProxy(proxyClass, interceptor));
//
} finally {
//设置构造函数不可访问
setConstructorsAccessible(mockedType, false);
}
//
}
生成过程中,设置了一个callback对象
private Object createProxy(Class<?> proxyClass, final MethodInterceptor interceptor) {
// 生成代理类实例,无构造函数生成实例是通过第三方的objenesis
Factory proxy = (Factory) objenesis.newInstance(proxyClass);
//指定callback实例为MethodInterceptorFilter对象
proxy.setCallbacks(new Callback[] { interceptor, NoOp.INSTANCE });
return proxy;
//
}
---接下来,如果执行
when(mock.test()).thenReturn(200);会发生什么呢?
Step completed: "thread=main", test.Test1.main(), line=19 bci=19
19 when(mock.test()).thenReturn(200);
main[1] step
>
Step completed: "thread=main", org.mockito.internal.creation.MethodInterceptorFilter.intercept(), line=35 bci=1
35 if (method.isBridge()) {
main[1]
可以看到,一下子就跳到了刚才埋点的callback实例了,这里不去研究为什么会到这里,牵扯的技术点太多,直接分析
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//是否是bridge方法?
// method = "public int test.Obj.test()"
if (method.isBridge()) {//这里为false
return methodProxy.invokeSuper(proxy, args);
}
//判断是否是equals方法
if (equalsMethod.equals(method)) {
return Boolean.valueOf(proxy == args[0]);
} else if (hashCodeMethod.equals(method)) {
//判断是否是hashCode方法
return hashCodeForMock(proxy);
}
//交给delegate来做,这里是一个MockHandler对象
return delegate.intercept(proxy, method, args, methodProxy);
}
下面转去看MockHandler对象怎么实现的
看到一个核心代码
Answer<?> answer = mockitoStubber.findAnswerFor(invocation);
if (answer != null) {
return answer.answer(invocation);
} else if (MockUtil.isMock(instance)) {
return Configuration.instance().getReturnValues().valueFor(invocation);
} else {
return methodProxy.invoke(instance, args);
}
因为之前没有打桩,所以这里执行
return Configuration.instance().getReturnValues().valueFor(invocation);
这个是根据方法的返回类型返回不同的对象
Object returnValueFor(Class<?> type) {
if (type.isPrimitive()) {
return primitiveOf(type);
} else if (Primitives.isPrimitiveWrapper(type)) {
return Primitives.primitiveWrapperOf(type);
// new instances are used instead of Collections.emptyList(), etc.
// to avoid UnsupportedOperationException if code under test
// modifies returned collection
} else if (type == Collection.class) {
return new LinkedList<Object>();
} else if (type == Set.class) {
return new HashSet<Object>();
} else if (type == HashSet.class) {
return new HashSet<Object>();
} else if (type == SortedSet.class) {
return new TreeSet<Object>();
} else if (type == TreeSet.class) {
return new TreeSet<Object>();
} else if (type == LinkedHashSet.class) {
return new LinkedHashSet<Object>();
} else if (type == List.class) {
return new LinkedList<Object>();
} else if (type == LinkedList.class) {
return new LinkedList<Object>();
} else if (type == ArrayList.class) {
return new ArrayList<Object>();
} else if (type == Map.class) {
return new HashMap<Object, Object>();
} else if (type == HashMap.class) {
return new HashMap<Object, Object>();
} else if (type == SortedMap.class) {
return new TreeMap<Object, Object>();
} else if (type == TreeMap.class) {
return new TreeMap<Object, Object>();
} else if (type == LinkedHashMap.class) {
return new LinkedHashMap<Object, Object>();
}
// Let's not care about the rest of collections.
return null;
}
普通类型返回则走下面的分支
private Object primitiveOf(Class<?> type) {
if (type == Boolean.TYPE) {
return false;
} else if (type == Character.TYPE) {
return (char) 0;
} else {
return 0;
}
}
比如我这里是int,则返回0,然后调用when()函数,这是返回一个OngoingStubbingImpl对象
然后调用这个对象的.thenReturn(200)函数
private class OngoingStubbingImpl implements NewOngoingStubbing<T>, DeprecatedOngoingStubbing<T> {
public NewOngoingStubbing<T> thenReturn(Object value) {
//这里
return thenAnswer(new Returns(value));
}
public NewOngoingStubbing<T> thenThrow(Throwable throwable) {
return thenAnswer(new ThrowsException(throwable));
}
public NewOngoingStubbing<T> thenAnswer(Answer<?> answer) {
//看到这里了
registeredInvocations.removeLast();
//这里加入用户设置的答案
mockitoStubber.addAnswer(answer);
return new ConsecutiveStubbing();
}
加入answer的大致过程
Step completed: "thread=main", org.mockito.internal.stubbing.MockitoStubber.addAnswer(), line=49 bci=66
49 stubbed.addFirst(new StubbedInvocationMatcher(invocationForStubbing, answer));
main[1] print stubbed
stubbed = "[]"
main[1] step
>
Step completed: "thread=main", org.mockito.internal.stubbing.MockitoStubber.addAnswer(), line=51 bci=69
51 }
main[1] print stubbed
stubbed = "[obj.test(); stubbed with: [org.mockito.internal.stubbing.Returns@62ee68d8]]"
到这里,打桩就全部结束了,下面开始调用
System.out.println(mock.test());
注意,这里调用了mock.test(),因为mock是一个代理示例,所以最终又调用了
org.mockito.internal.creation.MethodInterceptorFilter.intercept
//寻找是否有存在的打桩
Answer<?> answer = mockitoStubber.findAnswerFor(invocation);
if (answer != null) {
return answer.answer(invocation);
} else if (MockUtil.isMock(instance)) {
//看到这里了
return Configuration.instance().getReturnValues().valueFor(invocation);
} else {
return methodProxy.invoke(instance, args);
}
寻找过程是遍历
public Answer findAnswerFor(Invocation invocation) {
// 遍历stubbed--->LinkedList<StubbedInvocationMatcher>
for (StubbedInvocationMatcher s : stubbed) {
// 遍历每一个成员
if (s.matches(invocation)) {
return s;
}
}
return null;
}
最终返回的 结果为
Step completed: "thread=main", org.mockito.internal.MockHandler.intercept(), line=85 bci=187
85 Answer<?> answer = mockitoStubber.findAnswerFor(invocation);
main[1] step
>
Step completed: "thread=main", org.mockito.internal.MockHandler.intercept(), line=86 bci=189
86 if (answer != null) {
main[1] print answer
answer = "obj.test(); stubbed with: [org.mockito.internal.stubbing.Returns@62ee68d8]"
main[1] print answer.getClass()
answer.getClass() = "class org.mockito.internal.stubbing.StubbedInvocationMatcher"
然后就调用answer.answer(invocation)
后面大致就很清楚了。
public Object answer(InvocationOnMock invocation) throws Throwable {
//同步调用
synchronized(answers) {
return answers.size() == 1 ? //如果只有1个,就peek,保证不为空,否则poll
answers.peek().answer(invocation)
:
answers.poll().answer(invocation);
}
}
public Object answer(InvocationOnMock invocation) throws Throwable {
//返回你之前的埋点数据
return value;
}
大功告成。
总结:mock生成的是代理类,调用代理类的方法,实际上就是埋点打桩
告诉这个代理类,如果调用了这个方法,就埋上这个那个的返回结果。
最后把方法调用:结果--->一个注册表
---最后调用的时候,就从这个注册表里获取数据。