mockito创建mock对象的方式:
List list = mock(List.class);
现在我们来看看,这行代码到底在干什么?
(1)Mockito.java
/**
* 创建一个mock实例
*
* @param classToMock 需要mock的接口或者类
*/
public static <T> T mock(Class<T> classToMock) {
// [1]
return mock(classToMock, withSettings().defaultAnswer(RETURNS_DEFAULTS));
}
public static <T> T mock(Class<T> classToMock, MockSettings mockSettings) {
// 调用MockitoCore.mock方法
return MOCKITO_CORE.mock(classToMock, mockSettings);
}
[1] withSettings()返回的是mock的配置对象,由于配置对象包含的信息比较多,会在后面一一介绍。
(2)MockitoCore.java
/**
* 创建一个mock实例
*
* @param typeToMock 需要mock的接口或者类
* @param settings mock对象创建的配置
*/
public <T> T mock(Class<T> typeToMock, MockSettings settings) {
if (!MockSettingsImpl.class.isInstance(settings)) {
// 要求配置对象是MockSettingsImpl的实例
throw new IllegalArgumentException(
"Unexpected implementation of '" + settings.getClass().getCanonicalName() + "'\n"
+ "At the moment, you cannot provide your own implementations that class.");
}
// cast判断类型,其实上面的已经处理了,这里相当于强转
MockSettingsImpl impl = MockSettingsImpl.class.cast(settings);
// 校验配置对象(以后介绍)
MockCreationSettings<T> creationSettings = impl.confirm(typeToMock);
// [2]
T mock = mockUtil.createMock(creationSettings);
// [3]
mockingProgress.mockingStarted(mock, typeToMock);
return mock;
}
[2] 在此之前就是创建配置和校验配置操作,而mockUtil.createMock就是真正创建mock对象的方法
MockUtil.java
public <T> T createMock(MockCreationSettings<T> settings) {
// [4]
MockHandler mockHandler = new MockHandlerFactory().create(settings);
// [5]
T mock = mockMaker.createMock(settings, mockHandler);
// 说到spy在介绍
Object spiedInstance = settings.getSpiedInstance();
if (spiedInstance != null) {
new LenientCopyTool().copyToMock(spiedInstance, mock);
}
return mock;
}
[4]通过MockHandlerFactory创建mock的处理器对象,用于计算mock对象操作的结果
MockHandlerFactory.java
public InternalMockHandler create(MockCreationSettings settings) {
// 核心处理器
InternalMockHandler handler = new MockHandlerImpl(settings);
// 处理null和基本数据类型(静态代理)
InternalMockHandler nullResultGuardian = new NullResultGuardian(handler);
// 通知监听者
InternalMockHandler notifier = new InvocationNotifierHandler(nullResultGuardian, settings);
return notifier;
}
由于处理器功能比较复杂,在后面会专门介绍
[5]这里的mockMaker是全局变量,让我们看看这个变量是如何获得的
MockUtil.java
// 通过插件获取该对象
MockMaker mockMaker = Plugins.getMockMaker();
Plugins.java
public static MockMaker getMockMaker() {
// 再访问插件注册器
return registry.getMockMaker();
}
[6]
PluginRegistry.java
private final PluginSwitch pluginSwitch
= new PluginLoader(new DefaultPluginSwitch()).loadPlugin(PluginSwitch.class, DefaultPluginSwitch.class.getName());
private final MockMaker mockMaker
= new PluginLoader(pluginSwitch).loadPlugin(MockMaker.class, "org.mockito.internal.creation.cglib.CglibMockMaker");
MockMaker getMockMaker() {
return mockMaker;
}
[6] 由于PluginRegistry是一个独立的模块,这里直接介绍完:
(1)首先介绍PluginSwitch,它只有一个方法isEnabled(String pluginClassName),表示当前插件是否可用
(2)上面的代码在获取PluginSwitch对象时使用了PluginLoader.loadPlugin方法,来看一下这个方法在干嘛
PluginLoader.java
<T> T loadPlugin(Class<T> pluginType, String defaultPluginClassName) {
// 加载插件(核心方法)
T plugin = loadImpl(pluginType);
if (plugin != null) {
return plugin;
}
try {
// 如果插件没有找到就使用默认的插件类
return pluginType.cast(Class.forName(defaultPluginClassName).newInstance());
} catch (Exception e) {
throw new MockitoException("Internal problem occurred, please report it. " +
"Mockito is unable to load the default implementation of class that is a part of Mockito distribution. " +
"Failed to load " + pluginType, e);
}
}
<T> T loadImpl(Class<T> service) {
// 获取有效的类加载器
ClassLoader loader = Thread.currentThread().getContextClassLoader();
if (loader == null) {
loader = ClassLoader.getSystemClassLoader();
}
Enumeration<URL> resources;
try {
// 获取classpath下的mockito-extensions/插件名的文件
resources = loader.getResources("mockito-extensions/" + service.getName());
} catch (IOException e) {
throw new MockitoException("Failed to load " + service, e);
}
try {
// 简述过程:根据读取插件文件列表中的文件内容(文件中应该是插件的类全名),通过pluginSwitch控制某些插件不可用
String foundPluginClass = new PluginFinder(pluginSwitch).findPluginClass(Iterables.toIterable(resources));
if (foundPluginClass != null) {
// 创建插件实例
Class<?> pluginClass = loader.loadClass(foundPluginClass);
Object plugin = pluginClass.newInstance();
return service.cast(plugin);
}
return null;
} catch (Exception e) {
throw new MockitoConfigurationException(
"Failed to load " + service + " implementation declared in " + resources, e);
}
}
因为自带的代码中在classpath下不存在mockito-extensions目录,所以都是使用默认的插件类。即:PluginSwitch使用的插件类是DefaultPluginSwitch(所有的插件都是可用的),MockMaker使用的是CglibMockMaker(使用cglib创建mock对象,但是要求该对象不能是final修饰和基本数据类型)
说完插件,现在又回到我们的重点:[5]
MockUtil.java
T mock = mockMaker.createMock(settings, mockHandler);
从上面对插件的介绍可以得知,mockMaker是org.mockito.internal.creation.cglib.CglibMockMaker的实例,所以我们要看一下CglibMockMaker.createMock方法是如何实现的
CglibMockMaker.java
public <T> T createMock(MockCreationSettings<T> settings, MockHandler handler) {
// 校验并强转为InternalMockHandler对象,实际根据 new MockHandlerFactory().create(settings)创建handler实例的方式可以得知,handler是InvocationNotifierHandler的实例
InternalMockHandler mockitoHandler = cast(handler);
// 设置jvm序列化可用
new AcrossJVMSerializationFeature().enableSerializationAcrossJVM(settings);
// [7]
return new ClassImposterizer(new InstantiatorProvider().getInstantiator(settings)).imposterise(
// MethodInterceptorFilter会改变原有方法的行为
new MethodInterceptorFilter(mockitoHandler, settings), settings.getTypeToMock(), settings.getExtraInterfaces());
}
[7]new InstantiatorProvider().getInstantiator(settings)是用来获取创建实例的工具类对象
public Instantiator getInstantiator(MockCreationSettings settings) {
if (settings.isUsingConstructor()) {
// 如果配置中指定需要使用构造器创建实例,就返回ConstructorInstantiator对象
return new ConstructorInstantiator(settings.getOuterClassInstance());
} else {
return INSTANCE;
}
}
[7]new ClassImposterizer(new InstantiatorProvider().getInstantiator(settings))解读
CglibMockMaker.java
/**
* 如果settings指定需要使用构造器,就使用ConstructorInstantiator实例化
* @param settings mock配置对象
* @return
*/
public Instantiator getInstantiator(MockCreationSettings settings) {
if (settings.isUsingConstructor()) {
// 如果使用的是构造器创建实例,settings.getOuterClassInstance()对应的是构造器实参列表
return new ConstructorInstantiator(settings.getOuterClassInstance());
} else {
//Instantiator INSTANCE = new ObjenesisInstantiator(); 注意:Objenesis可以绕开对象实例构造器实例化对象
return INSTANCE;
}
}
imposterise方法介绍:
ClassImposterizer.java
/**
* 创建代理class对象
* @param interceptor 方法拦截器,修改原有方法的处理逻辑
* @param mockedType mock对象继承类或者实现的接口
* @param ancillaryTypes mock对象需要额外实现的接口列表
* @return
*/
public <T> T imposterise(final MethodInterceptor interceptor, Class<T> mockedType, Class<?>... ancillaryTypes) {
Class<Factory> proxyClass = null;
Object proxyInstance = null;
try {
// 设置构造器可访问权限
setConstructorsAccessible(mockedType, true);
// [8]
proxyClass = createProxyClass(mockedType, ancillaryTypes);
// [9]
proxyInstance = createProxy(proxyClass, interceptor);
return mockedType.cast(proxyInstance);
} catch (ClassCastException cce) {
throw new MockitoException(join(
"ClassCastException occurred while creating the mockito proxy :",
" class to mock : " + describeClass(mockedType),
" created class : " + describeClass(proxyClass),
" proxy instance class : " + describeClass(proxyInstance),
" instance creation by : " + instantiator.getClass().getSimpleName(),
"",
"You might experience classloading issues, disabling the Objenesis cache *might* help (see MockitoConfiguration)"
), cce);
} finally {
setConstructorsAccessible(mockedType, false);
}
}
[8]代理的class对象
/**
* 创建代理class对象
* @param mockedType mock对象继承类或者实现的接口
* @param interfaces mock对象需要额外实现的接口列表
* @return
*/
public Class<Factory> createProxyClass(Class<?> mockedType, Class<?>... interfaces) {
if (mockedType == Object.class) {
// 定义一个特殊类(没有任何字段和方法,相当于Object但是类型更明确)
mockedType = ClassWithSuperclassToWorkAroundCglibBug.class;
}
Enhancer enhancer = new Enhancer() {
@Override
@SuppressWarnings("unchecked")
protected void filterConstructors(Class sc, List constructors) {
// Don't filter
}
};
// 所有的mock类型(mock类型和接口类型)
Class<?>[] allMockedTypes = prepend(mockedType, interfaces);
// 设置类加载器
enhancer.setClassLoader(SearchingClassLoader.combineLoadersOf(allMockedTypes));
enhancer.setUseFactory(true);
if (mockedType.isInterface()) {
// mock类型是接口
enhancer.setSuperclass(Object.class);
// 设置所有需要实现的接口列表
enhancer.setInterfaces(allMockedTypes);
} else {
// 如果mock是类
enhancer.setSuperclass(mockedType);
enhancer.setInterfaces(interfaces);
}
// 设置方法拦截器
enhancer.setCallbackTypes(new Class[]{MethodInterceptor.class, NoOp.class});
// 设置方法过滤(不拦截桥接方法)
enhancer.setCallbackFilter(IGNORE_BRIDGE_METHODS);
// 设置命名策略,默认的是:被代理class name + "$$" + 使用cglib处理的class name + "ByCGLIB" + "$$" + key的hashcode,示例:FastSource$$FastClassByCGLIB$$e1a36bab.class
if (mockedType.getSigners() != null) {
// 类标识存在
enhancer.setNamingPolicy(NAMING_POLICY_THAT_ALLOWS_IMPOSTERISATION_OF_CLASSES_IN_SIGNED_PACKAGES);
} else {
enhancer.setNamingPolicy(MockitoNamingPolicy.INSTANCE);
}
enhancer.setSerialVersionUID(42L);
try {
// 创建实例
return enhancer.createClass();
} catch (CodeGenerationException e) {
if (Modifier.isPrivate(mockedType.getModifiers())) {
throw new MockitoException("\n"
+ "Mockito cannot mock this class: " + mockedType
+ ".\n"
+ "Most likely it is a private class that is not visible by Mockito");
}
throw new MockitoException("\n"
+ "Mockito cannot mock this class: " + mockedType
+ "\n"
+ "Mockito can only mock visible & non-final classes."
+ "\n"
+ "If you're not sure why you're getting this error, please report to the mailing list.", e);
}
}
/**
* 合并多个class对象
* @param first
* @param rest
* @return
*/
private Class<?>[] prepend(Class<?> first, Class<?>... rest) {
Class<?>[] all = new Class<?>[rest.length+1];
all[0] = first;
System.arraycopy(rest, 0, all, 1, rest.length);
return all;
}
[9]创建代理实例
/**
* 创建代理对象
* @param proxyClass 代理类的class对象
* @param interceptor 方法拦截器
* @return
*/
private Object createProxy(Class<Factory> proxyClass, final MethodInterceptor interceptor) {
Factory proxy;
try {
// 使用实例化器创建代理对象(支持构造器和Objenesis创建实例)
proxy = instantiator.newInstance(proxyClass);
} catch (InstantationException e) {
throw new MockitoException("Unable to create mock instance of type '" + proxyClass.getSuperclass().getSimpleName() + "'", e);
}
// 设置拦截
proxy.setCallbacks(new Callback[] {interceptor, SerializableNoOp.SERIALIZABLE_INSTANCE });
return proxy;
}