单元测试

mockito源码研究之verify

2018-06-10  本文已影响584人  天外流星for

一、Mockito类相当于整个框架的门面,负责对外提供调用接口。常用的有如下几个:

mock

  List list = Mockito.mock(List.class);  此时, list就是被Mockito所mock后生成的实例,Mockito会记住它所mock对象的所有调用,为后面的验证做准备。

when

  Mockito.when(list.size()).thenReturn(1);

上述代码表示,当对list对象调用size()方法时,会返回1.这样我们就可以自定义mock对象的行为了。

verify

  Mockito.verify(list).add(Matchers.anyObject());

  Mockito.verify(reserveManager).findByTradeOrderId(Mockito.any());

  Mockito.verify(reserveManager,Mockito.times(1)).findByTradeOrderId(Mockito.any());  Mockito.times(1):执行次数

verify是负责验证的函数,接受的参数是一个被mock的对象,表示验证其是否执行了后面的方法。

二、疑问点

verify函数怎么会知道哪些方法被调用了呢?是动态代理吗?

三、源码深入

1. 入口类Mockito

public static T verify(T mock, VerificationMode mode) {    // 常用的验证模式: AtLeast(最少)、AtMost(最多)、Times(次数)

   return MOCKITO_CORE.verify(mock, mode);  // 

}

2. 核心实现逻辑

public T verify(T mock, VerificationMode mode) {

if (mock ==null) {

throw nullPassedToVerify();

    }

if (!isMock(mock)) {

throw notAMockPassedToVerify(mock.getClass());

    }

    MockingProgress mockingProgress =mockingProgress();

    VerificationMode actualMode = mockingProgress.maybeVerifyLazily(mode);

    mockingProgress.verificationStarted(new MockAwareVerificationMode(mock, actualMode, mockingProgress.verificationListeners()));

    return mock;

}

>>> 可见verify函数只是做了一些准备工作, 首先,VerificationMode是对验证信息的封装,它是一个接口,含有verify函数, 例如我们常用的never(). times(1)返回的都是Times类型,而Times类型就是VerificationMode的一种实现。然后,调用mockingProgress 来缓存mode信息。

>>>  函数的最后直接将mock对象返回,VerificationMode并没有被执行,因为在verify函数后紧跟着就是调用mock对象的doSome()方法。

3. 抽象验证类(MockAwareVerificationMode)

public void verify(VerificationData data) {

try {

       mode.verify(data);  // 通过传入的验证模式来验证数据,这里是一个命令模式,将动作的执行,封装在命令中。

        notifyListeners(new VerificationEventImpl(mock, mode, data, null));  // 这里是一个观察者模式,将验证数据广播出去

    }catch (RuntimeException e) {

notifyListeners(new VerificationEventImpl(mock, mode, data, e));

        throw e;

    }catch (Error e) {

notifyListeners(new VerificationEventImpl(mock, mode, data, e));

        throw e;

    }

}

4. Times模式的验证

public void verify(VerificationData data) {

List invocations = data.getAllInvocations();

    MatchableInvocation wanted = data.getTarget();

    if (wantedCount >0) {

       checkMissingInvocation(data.getAllInvocations(), data.getTarget());  // 这里只是作为一种日志补偿输出

    }

       checkNumberOfInvocations(invocations, wanted, wantedCount);  // 将缓存的调用信息与期望值进行比较

}

5. verify.doSome() 实现

MockHandlerImpl的handle

VerificationMode verificationMode = mockingProgress.pullVerificationMode();

if (verificationMode != null) {

if (((MockAwareVerificationMode) verificationMode).getMock() == invocation.getMock()) {

VerificationDataImpl data = createVerificationData(invocationContainerImpl, invocationMatcher);

verificationMode.verify(data); return null; }

else { ... }

}

先获取mockingProgress中缓存的verificationMode信息,然后当验证信息不为空时,验证mode的状态是否正确,当一切无误是调用verificationMode的verify方法,完成验证

6. 方法拦截源码:SubclassBytecodeGenerator

public ClassmockClass(MockFeatures features) {

DynamicType.Builder builder =

byteBuddy.subclass(features.mockedType)

.name(nameFor(features.mockedType))

.ignoreAlso(isGroovyMethod())

.annotateType(features.mockedType.getAnnotations())

.implement(new ArrayList(features.interfaces))

.method(matcher)

.intercept(to(DispatcherDefaultingToRealMethod.class))

.transform(withModifiers(SynchronizationState.PLAIN))

.attribute(INCLUDING_RECEIVER)

.method(isHashCode())

.intercept(to(MockMethodInterceptor.ForHashCode.class))

.method(isEquals())

.intercept(to(MockMethodInterceptor.ForEquals.class))

.serialVersionUid(42L)

.defineField("mockitoInterceptor", MockMethodInterceptor.class, PRIVATE)

.implement(MockAccess.class)

.intercept(FieldAccessor.ofBeanProperty());

上一篇下一篇

猜你喜欢

热点阅读