1基本的使用步驟
1,環(huán)境使用mock和test包
2,使用mockitoRule構(gòu)造mockito環(huán)境
@Rule
public MokitoRule rule = MockitoJUnit.rule();
注意這里的修飾符public,如果沒有這個修飾符的話使用mock測試會報錯
?@Rule
?public ExpectedException thrown = ExpectedException.none();
可以選擇忽視拋出的異常?(我是這么理解的不知道是否正確)
3,對目標測試類加@InjectMocks注解
4,對目標測試類的依賴屬性使用@mock創(chuàng)建依賴
5,使用@test注解測試目標類的方法執(zhí)行邏輯
2mock對象創(chuàng)建和目標測試類的依賴注入
這里我還沒有看juint執(zhí)行的邏輯,只是看了mock環(huán)境下獲取注解創(chuàng)建mock對象,并將mock的對向注入到@Injectmocks的目標測試對象中去的邏輯。
1,測試前的準備
使用的jar包版本是junit.junit.4.11,org.powermock.powermock-api-mockito.1.6.6
創(chuàng)建一個interface用于目標測試類的filed的type。
public interface MyInterface { public void show(); }
創(chuàng)建一個目標測試類,其中聲明filed的type為上面的interface的type
public class DoMainObject {
private MyInterface a;
private MyInterface b;
public void aShow(){a.show();}
public void bShow(){b.show();}
}
最后創(chuàng)建一個測試用例對象用于測試目標測試類
public class MyMockTest {
@Rule public MockitoRule mockito = MockitoJUnit.rule();//創(chuàng)建mockito的rule
@Rule public ExpectedException thrown = ExpectedException.none();//忽視異常
@InjectMocks private DoMainObject doMainObject;//目標測試類
@Mock private MyInterface a;//目標測試類的field a
@Mock private MyInterface b;//目標測試類的filed b
@Test public void testShow(){
doMainObject.aShow();
doMainObject.bShow();
}
}
2進行debug測試
1測試類中加斷點debug
我從rule對象執(zhí)行的時候開始追蹤,junit的運行原理略過

2,initmocks方法內(nèi)部

其中的testClass就是測試用例,MyMockTest的實例,annotationEngine是默認的注解驅(qū)動InjectingAnnotationEngine,
這個方法的內(nèi)部獲取測試用例的type,獲取注解驅(qū)動,并判斷是否是默認的注解驅(qū)動,可以自定義注解驅(qū)動?(暫時我還辦不到),之后注解驅(qū)動執(zhí)行
3, InjectingAnnotationEngine .process方法

InjectingAnnotationEngine.process 內(nèi)部只有兩個方法,從名字和其上的注釋可以知道
processIndependentAnnotations處理獨立的filed,其實就是測試用例中有@mock注解的filed,這里就是a和b。processInjectMocks處理依賴于獨立mock對象的filed,就是測試用例中有@InjectMocks注解的filed,依賴于mock對象的目標測試類,這里就是DoMainObject,先看processInjectMocks
4, processIndependentAnnotations


入?yún)⒎謩e為測試用例的type,和instance,方法中只有一個循環(huán),在循環(huán)的內(nèi)部處理三件事
1delegate.process(classContext, testInstance);委派對象處理@Mock,@Captor等注解,
2spyAnnotationEngine.process(classContext, testInstance);監(jiān)視注解驅(qū)動處理@Spy注解
3獲取測試用例的父類,賦值給原來的變量
4如果Class的type為Object,跳出循環(huán)
這個方法就是先處理自己的獨立注解,然后去處理父類的獨立注解,如此往復(fù)直到父類為Object源類。
5delegate.process

這個方法參數(shù)還是Class的type和Class 的instance,
處理過程是獲取instance的所有field就是所有的屬性,然后循環(huán)獲取filed的上的所有注解,更具注解和field嘗試創(chuàng)建mock對象,這里最后的創(chuàng)建對象時使用cblib創(chuàng)建代理對象,最后創(chuàng)建一個Setter對象將創(chuàng)建的cglib代理對象mock對象,set進instance的field中去,即完成了一個測試用例中的屬性的注入(spring的bean注解注入方式是不是也是如此呢,所有的基于注解的實現(xiàn)原理是否基本類似于此呢)
這里只關(guān)注兩個方法createMockFor和FieldSetter(testInstance, field).set(mock)
6, DefaultAnnotationEngine.?createMockFor
createMockFor方法的流程比較復(fù)雜,

這個方法的內(nèi)部有兩個方法,
DefaultAnnotationEngine.forAnnotation(),

在這個方法中對annotationd的類型與已有的注解處理器對象集合進行判斷是否包含,如果包含取出對應(yīng)的處理器對象,如果不包含空實現(xiàn)一個注解處理器實現(xiàn)process方法返回為null。也就是說在DefaultAnnotationEngine對象的實例中只處理特定的注解生成其mock代理對象。
這個注解處理器的集合是在4中創(chuàng)建了deletage時創(chuàng)建了DefaultAnnotationEngine對象,然后在其構(gòu)造方法中調(diào)用了注冊注解驅(qū)動方法
private final Map, FieldAnnotationProcessor?> annotationProcessorMap = new HashMap, FieldAnnotationProcessor>();
? ? public DefaultAnnotationEngine() {
? ? ? ? registerAnnotationProcessor(Mock.class, new MockAnnotationProcessor());
? ? ? ? registerAnnotationProcessor(MockitoAnnotations.Mock.class, new MockitoAnnotationsMockAnnotationProcessor());
? ? ? ? registerAnnotationProcessor(Captor.class, new CaptorAnnotationProcessor());
? ? }
private void registerAnnotationProcessor(Class annotationClass, FieldAnnotationProcessor fieldAnnotationProcessor) {
? ? ? ? annotationProcessorMap.put(annotationClass, fieldAnnotationProcessor);
? ? }
DefaultAnnotationEngine.process()
根據(jù)獲取的annotationProcess對象執(zhí)行process方法,如果不是從map中獲取的那么返回值就是null,在本測試中就是@mock的方法返回了MockAnnotationProcessor類型的注解驅(qū)動,

Mockito.mock(field.getType(), mockSettings);這個就是最后創(chuàng)建mock的cglib代理對象的方法,對這個方法暫時就不繼續(xù)追蹤了,
小結(jié)
現(xiàn)在我們已經(jīng)將一個@Mock注解下的測試類中的field建立好了,讓我們回到5的process方法中,能看見這個步驟就是重復(fù)的執(zhí)行這段邏輯:
獲取field的所有注解,調(diào)用createMockFor方法,然后在此方法中和DefaultAnnotationEngine預(yù)置的FieldAnnotationProcessor 實現(xiàn)類型集合做匹配,滿足的獲取指定的注解處理器創(chuàng)建對應(yīng)的mock對象。不滿足的創(chuàng)建一個匿名子類,其中實現(xiàn)的方法指定返回null。以此將@Mock等注解和其他注解區(qū)分開來,只創(chuàng)建@Mock和@Captor等獨立的注解。如此步驟processIndependentAnnotations.process()就完成了。
spyAnnotationEngine.process的執(zhí)行類似,但是這個注解處理類是使用反射去根據(jù)類型創(chuàng)建一個真實的實例對象返回而不是創(chuàng)建一個mock的cglib對象。
7,InjectingAnnotationEngine .processInjectMocks
現(xiàn)在我們完成了processIndependentAnnotations,來看看現(xiàn)在的測試用例instance

可以看到現(xiàn)在a,b使用@Mock注解的field已經(jīng)存在cglib的代理對象了,使用@InjectMocks的doMainObject暫時還是null,現(xiàn)在來看processInjectMocks

方法內(nèi)部的核心方法是injectMocks,內(nèi)部的邏輯從子類到父類最后到Object處理每個繼承層級的@InjectMocks注解
8 .InjectingAnnotationEngine.injectMocks

方法內(nèi)處理
1獲取測試用例的Class類型
2創(chuàng)建一個Field對象的set集合
3循環(huán)處理
4將class中所有InjectMocks注解的field放到mockDependentFields集合中
5將創(chuàng)建的mock對象添加到mocks集合中
6Class類型是Object跳出循環(huán)
7創(chuàng)建@InjectMock注解修飾的field
9DefaultInjectionEngine.injectMocksOnFields
這是根據(jù)依賴創(chuàng)建目標測試類的mock對象。

最后方法完成的時候

可以看到目標測試類創(chuàng)建完成,依賴a,b也已經(jīng)注入。
3,總結(jié)
沒有去追蹤Junit和cglib只是將中間mock的注解的過程進行了追蹤:
基本就是先創(chuàng)建mock對象,然后將根據(jù)依賴創(chuàng)建@InjectMocks的目標測試類對象
其中注解的區(qū)分
1@InjectMocks和其他類型不同,
2@Spy和@Mock,@Captor等注解不同
4,注意
在使用的過程中Rule一定要是pulic修飾的
在使用mockito的時候還出現(xiàn)了mock的對象在測試的時候報空指針的問題,我追蹤后發(fā)現(xiàn)是同類型的interface在注入@InjectMocks修飾的主目標對象的時候是有排序的,會根據(jù)測試類中的filedName進行排序依次向下注入,解決辦法就是把@InjectMocks的所有field都進行mock。