mockito源碼研究之verify

一、Mockito類相當(dāng)于整個(gè)框架的門面,負(fù)責(zé)對(duì)外提供調(diào)用接口。常用的有如下幾個(gè):

mock

? List list = Mockito.mock(List.class);? 此時(shí), list就是被Mockito所mock后生成的實(shí)例,Mockito會(huì)記住它所mock對(duì)象的所有調(diào)用,為后面的驗(yàn)證做準(zhǔn)備。

when

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

上述代碼表示,當(dāng)對(duì)list對(duì)象調(diào)用size()方法時(shí),會(huì)返回1.這樣我們就可以自定義mock對(duì)象的行為了。

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):執(zhí)行次數(shù)

verify是負(fù)責(zé)驗(yàn)證的函數(shù),接受的參數(shù)是一個(gè)被mock的對(duì)象,表示驗(yàn)證其是否執(zhí)行了后面的方法。

二、疑問點(diǎn)

verify函數(shù)怎么會(huì)知道哪些方法被調(diào)用了呢?是動(dòng)態(tài)代理嗎?

三、源碼深入

1. 入口類Mockito

public static T verify(T mock, VerificationMode mode) {? ? // 常用的驗(yàn)證模式:?AtLeast(最少)、AtMost(最多)、Times(次數(shù))

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

}

2. 核心實(shí)現(xiàn)邏輯

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函數(shù)只是做了一些準(zhǔn)備工作, 首先,VerificationMode是對(duì)驗(yàn)證信息的封裝,它是一個(gè)接口,含有verify函數(shù), 例如我們常用的never(). times(1)返回的都是Times類型,而Times類型就是VerificationMode的一種實(shí)現(xiàn)。然后,調(diào)用mockingProgress 來緩存mode信息。

>>>? 函數(shù)的最后直接將mock對(duì)象返回,VerificationMode并沒有被執(zhí)行,因?yàn)樵趘erify函數(shù)后緊跟著就是調(diào)用mock對(duì)象的doSome()方法。


3. 抽象驗(yàn)證類(MockAwareVerificationMode)

public void verify(VerificationData data) {

try {

? ? ? ?mode.verify(data);? // 通過傳入的驗(yàn)證模式來驗(yàn)證數(shù)據(jù),這里是一個(gè)命令模式,將動(dòng)作的執(zhí)行,封裝在命令中。

? ? ? ? notifyListeners(new VerificationEventImpl(mock, mode, data, null));? // 這里是一個(gè)觀察者模式,將驗(yàn)證數(shù)據(jù)廣播出去

? ? }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模式的驗(yàn)證

public void verify(VerificationData data) {

List invocations = data.getAllInvocations();

? ? MatchableInvocation wanted = data.getTarget();

? ? if (wantedCount >0) {

? ? ? ?checkMissingInvocation(data.getAllInvocations(), data.getTarget());? // 這里只是作為一種日志補(bǔ)償輸出

? ? }

? ? ? ?checkNumberOfInvocations(invocations, wanted, wantedCount);? // 將緩存的調(diào)用信息與期望值進(jìn)行比較

}


5.?verify.doSome() 實(shí)現(xiàn)

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信息,然后當(dāng)驗(yàn)證信息不為空時(shí),驗(yàn)證mode的狀態(tài)是否正確,當(dāng)一切無誤是調(diào)用verificationMode的verify方法,完成驗(yàn)證

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());

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容