Mockito 原理解析

一.介绍

mockito 是java流行的mock框架,通过该框架来完成一些集成测试和单元测试。

二.原理

mocktio主要是使用代理模式来设计,mockitio采用byte buddy框架生成一个动态代理对象,为mock对象的每个方法都做了拦截。只要调用mock对象则会直接调用拦截器方法。

mocktio主要流程分为以下三部分,也是主要使用方式:

  1. 创建mock对象
  2. 设置mock行为
  3. 执行mock方法

这三个步骤代码如下:

1
2
3
4
5
6
7
8
// 1. 创建mock对象
List list = Mockito.mock(List.class);

// 2. 设置mock行为
Mockito.when(mock.add("test")).thenReturn(true);

// 3. 执行mock方法
System.out.println(mock.add("test"));

本文将根据以上三个步骤来解析整个过程。

2.1 数据结构

首先需要说明mocktio内部的数据结构

MockHandler

mockito会为每个创建的mock对象创建一个MockHandler, 它的实现类是MockHandlerImpl。该对象主要用于处理mock对象的每个被拦截方法。执行每个拦截方法的时候,都会交给这个handler处理。
一个mock对象对应一个MockHandler

该方法中有两个重要的结构:

  1. OngoingStubbingImpl 是一个桩实现,是mock方法的一个包装。会为每个mock对象的方法创建一个OngoingStubbingImpl,用来监控和模拟该方法行为。如上面mock.add(“test”)行为。一个mock方法对应多个OngoingStubbingImpl,其实每调用一次mock方法都会创建一个OngoingStubbingImpl对象。
  2. MockingProgress。 用来存放正在mock中的数据,如OngoingStubbingImpl。采用了ThreadLocal方式实现,保证了线程安全。

2.2 创建mock对象

mock对象的创建主要是为了创建一个mock对象的代理类,使得代理类代理mock对象的所有方法(从源码设计中包含了私有方法,但是受私有方法封装性原因,该私有方法无法进行mock).
根据代理模式,要实现这个过程首先是需要创建一个类,该类继承了被代理类,并且对每个方法进行拦截。在拦截方法中实现mock逻辑。

mock实例方法的场景利用了Java运行时多态的原理,通过重写父类的方法来修改某个方法的行为。

mockito首先接受一个指定的class类型,采用java的动态代理逻辑,使用了ByteBuddy框架来生成该class类型的代理实例。代理对象继承了被mock类,为了对每个方法做拦截,通过byte buddy设置拦截器 MockMethodInterceptor。MockMethodInterceptor的主要作用是将mock对象的拦截方法执行交给了MockHandler来处理。

1
2
3
4
5
6
7
8
// 使用byte buddy 生成一个class 
Class<? extends T> mockedProxyType = createMockType(settings);
// 通过class 生成一个对象
mockInstance = instantiator.newInstance(mockedProxyType);

// 设置拦截器,并handler设置到mock对象中
MockAccess mockAccess = (MockAccess) mockInstance;
mockAccess.setMockitoInterceptor(new MockMethodInterceptor(handler, settings));

2.3 设置mock行为

该部分主要分为三个步骤:

  1. mock.doSome(): 为mock方法设置OngoingStubbingImpl,并存放在ThreadLocal中。
  2. 执行when方法:执行when方法从mock对象的ThreadLocal中获得mock方法的桩对象OngoingStubbingImpl
  3. 设置mock行为。对OngoingStubbingImpl设置mock行为,如thenReturn、thenThrow等。

when

1
Mockito.when(mock.add("test")).thenReturn(true);

执行以上代码,如何为mock.add(“test”)方法设置拦截,使得调用mock.add(“test”)时返回true呢?when的方法

其主要巧妙的运用的ThreadLocal特性,同时通过对使用规范的限制来保证整个逻辑能够正确执行。

在执行when的时候 mocktio要求执行mock对象的mock方法,即mock.doSome(),如mock.add(“test”)。 执行完成后,在执行when,通过when方法获取该mock方法对应的OngoingStubbingImpl,用于后面设置对应的操作。

在执行 mock.doSome()

thenReturn

参考

0%