2 回答

TA貢獻1806條經(jīng)驗 獲得超8個贊
如何用mockito+spring進行單元測試(1)
本文只說如何使用。
假設你和我一樣,也要構(gòu)造一個系統(tǒng),系統(tǒng)中有若干service,假設是A,B,C吧。
其中A 依賴 B 依賴 C。C是最基本的。
現(xiàn)在需要對A進行單測,但是C需要依賴于外部環(huán)境,而這個環(huán)境需要復雜而且不穩(wěn)定的數(shù)據(jù)庫。怎么辦呢?這時你就需要mock掉C。
第一步你需要在appctx文件中申明:
<bean id="serviceC" name="service_c_Mock" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.x.y.x.ServiceC"></constructor-arg>
</bean>
需要注意的是bean的id必須要和A和B中autowire時使用名字一致?;蛘哂妙愋鸵残小?br/> 然后在單測case中用@Mock或者@Resource引入sercieC。接著在單測case的Setup中調(diào)用如下語句。
MockitoAnnotations.initMocks(this);
這時你測試A的方法,A訪問B,B訪問C時,調(diào)用會落在mockito生成的一個代理上。這個時候所調(diào)用的任何方法都會返回null。
這可能不是你期望的,你可能期望在A用到的那些些方法上,輸入某個值時返回某個特定的值。這個時候你需要:
when().then();
如果這還不夠,你希望他輸入某個值的時候返回特定值,如果輸入的值不是特定值的時候,返回正常邏輯的值,你需要spy,并傳入一個serviceC的實現(xiàn)。
這個方法也解決了那個對于不mock的方法進行返回的問題。

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