以前寫過一篇blog,寫得不是很詳細。這次清明節在家好好的整理了下思路,把相關的細節重寫下來。很奇怪這些內容在google上找不到,也許是太基本了吧。
為了理解mockito,必須先明白mock測試的原理,它分成以下幾個步驟:
| 建立mock; |
| 將mock和待測試的對象連接起來; |
| 在mock上設置預期的返回值; |
| 開啟replay模式,准備記錄實際發生的調用; |
| 進行測試; |
| 驗證測試結果,調用順序是否正確,返回值是否符合期望; |
本文主要講第一步和第二步。
對於Mockito而言,有兩種方式創建:
- 1. mock為一個interface提供一個虛擬的實現,
- 2. spy為object加一個動態代理,實現部分方法的虛擬化。
假設待測試的class聲明如下:
public class Svc{
DaoInterface dao1;
DaoInstance dao2;
…
你可以用如下的聲明得到一個Interface的mock,或者一個實例的spy,並把它注入到測試對象中:
| private Svc svc; @Before public void setup(){ mockdao = mock(DaoInterface.class); } |
private Svc svc; @Before public void setup(){ tmp= new DaoInstance (); spydao = spy(tmp); } |
請注意到spy和mock的不同。但是spy並不是很好的實踐,因為它意味着你的代碼不能很好的將變化的部分分離開來。因此最好只在那些歷史遺留系統上使用。
上面這種方式並不唯一的途徑。為了避免重復代碼,Mockito提供了幾個注解:
@Mock,被標注的屬性是個mock
@Spy,被標注的屬性是個spy,需要賦予一個instance
@InjectMocks,將本test中的mock或者spy注入到被標注的屬性中,根據構造函數的參數名,或者setter,或者私有屬性名。
最后在setup中調用MockitoAnnotations.initMocks(this);就免去了代碼的編寫。如下所示:
| private @InjectMocks Svc svc; @Before public void setup(){ //mockdao = mock(DaoInterface.class); MockitoAnnotations.initMocks(this); } |
private @InjectMocks Svc svc; DaoInstance() ; @Before public void setup(){ // tmp= new DaoInstance (); // spydao = spy(tmp); MockitoAnnotations.initMocks(this); } |
如果你使用spring,上述代碼還可以進一步簡化,因為Mockito提供了factory的方法用來創建mock和spy。
| 正常的bean聲明 | <bean id=”svc” class=”Svc”> <bean id=”dao1” class=”…”> <bean id=”dao2” class=”…”> |
| mock | <bean id="dao1" class="org.mockito.Mockito" factory-method="mock"> 請注意到svc不變化,mock將自動注入進入。這是因為spring的bean容器,如果id一樣,后聲明的bean會覆蓋前面的bean。 |
| spy | <bean id="daoInst" class="DaoInstance"> 同樣svc不變化,直接注入。請注意spy需要獲得一個實例。 |
然后你只需要對dao1和dao2進行方法設置就可以了。
