Mockito-1.6原理浅析

为了节省时间,找了一个早期的版本来理解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生成的是代理类,调用代理类的方法,实际上就是埋点打桩

告诉这个代理类,如果调用了这个方法,就埋上这个那个的返回结果。

最后把方法调用:结果--->一个注册表

---最后调用的时候,就从这个注册表里获取数据。

 

 

 

转载于:https://my.oschina.net/qiangzigege/blog/831555

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值