提公升單元測試體驗的利器 Mockito使用總結

2021-09-20 07:43:51 字數 3077 閱讀 9961

在編寫單元測試的時候,為了盡可能的保證隔離性,我們時常需要對某些不容易構造或者不容易獲取或者對外部環境有依賴的物件,用乙個虛擬的物件來建立以便於測試.假設你正在開發的的**中使用到了公司其他部門的介面(通過rpc服務),當編寫單元測試的時候你可能為了不讓介面真的去呼叫rpc服務而mock乙個介面的物件,最原始的方式是自己手工編寫乙個該介面的實現類,並且在單元測試的時候注入這個物件,而使用mockito則可以讓我們方便地建立和配置mock物件,使用mockito可以簡化對外部環境的依賴.

這裡我們以乙個操作redis的工具類來舉例,下面是**:

public

class

redisutil

public

void

setvaluebykey(string key, string value)

public

string getvaluebykey(string key)

public listgetmutivaluesbylist(listkeys)

public

void

deletekey(string key)

public

void

increvalue(string key,long count)

}

有兩種方式可以方便的建立mock物件,第一種方式是

mockito.mock(redisutil.class);

還有一種方式在注入時使用@mock註解:

@mock

private redisutil redisutil;

tips:如果在**中頻繁的使用mockito比較煩,可以靜態匯入package,以下例子全部預設已靜態匯入mockito包:

import

static org.mockito.mockito.*;

當物件被建立之後,就可以對****現的方法進行自定義的互動,mock物件會記住這些互動,在單元測試的執行中碰到**中的對應方法會預設執行被你自定義的方法內容.

還是以redisutil為例,對方法設定返回值:

when(redisutil.getvaluebykey("key1")).thenreturn("value1");

when(redisutil.getvaluebykey("key2")).thenreturn("value2");

對方法設定返回自定義的異常資訊:

when(redisutil.getvaluebykey("key1")).thenthrow(new runtimeexception);

此外mockito還支援迭代風格的返回值定義:

when(redisutil.getvaluebykey("key1")).thenreturn("value1").thenreturn("value2");

即當方法第一次呼叫redis.getvaluebykey("key1")時會返回value1,當再次被呼叫時則會返回value2.這裡需要注意的是,當後續再出現呼叫的時候返回值都會是value2,而且這種迭代風格的定義支援return和throw的混搭,即你可以控制在函式呼叫的第一次去丟擲乙個異常,而在函式呼叫的第二次繪製乙個正常的值.

首先,測試中對於返回值為void 的方法進行mock本身是沒有什麼效果的,mockito有乙個donothing方法是void方法的預設返回:

donothing().when(redisutil).increvalue(「key1",1l);

其實這裡使用donothing來mock這個方法並沒有什麼意義,因為我們mock乙個方法的目的無非有兩個,第一,在某一中輸入環境中模擬返回我們期待的返回值,第二就是當方法丟擲異常時能夠在我們預期控制之下而不會導致單元測試失敗,因此對於返回值為void的方法,我們一般可以不去mock它或者使用dothrow()來為void函式打乙個樁,當出現異常的時候mock他的異常返回,當不會有異常發生時,只需要在呼叫後,verify()一下,驗證方法的被呼叫次數即可.

verify(redisutil,times(1)).increvalue("key1",1l);

**中的times(1)表示一次,即**中increvalue()返回被呼叫一次的時候能夠通過,還可以支援更加廣泛的定義,

never():表示從未被呼叫

atleastonce():表示至少被呼叫一次

atleast(3):表示至少被呼叫3次

atmost(7):表示最多被呼叫7次

這裡主要介紹一下內建的幾個引數匹配器,其實也很好理解,還是那上面的redisutil為例,對於redisutil.getvaluebykey來說,我希望對於任意的key都返回同乙個值,那就可以這麼寫:

when(redisutil.getvaluebykey(anystring()).thenreturn("value1")

這樣在單元測試過程中,對於任意的輸入引數,該方法都會返回value1,相同的型別還有很多anylong(),anyint(),anylist()等等

以上所講的物件都是mock物件,mock物件只能呼叫打樁方法,不能呼叫真實方法,使用spy可以讓我們能夠監視乙個真實物件,既可以對這個物件的某乙個函式打樁返回我們期望的值,也可以去呼叫真實的方法,建立spy物件的方式和mock類似,不同的一點是spy需要傳乙個真實物件而不是乙個class物件.這裡以乙個list為例,

list spy = spy(new

linkedlist());

when(spy.get(0)).thenreturn("value1");

doreturn("value2").when(spy).get(0);

上面第二行**,呼叫when(spy.get(0)),會去呼叫真實的方法,會丟擲異常,第三行**則不會去呼叫真實方法,而返回value2.所以總結一下就是,當使用when去模擬返回值的時候,真是方法會被呼叫,而是用doreturn()去設定的話,則不會去執行真實方法.

需要注意在使用時應該盡量避免使用spy.

mockito文件

提公升單元測試體驗的利器 Mockito使用總結

在編寫單元測試的時候,為了盡可能的保證隔離性,我們時常需要對某些不容易構造或者不容易獲取或者對外部環境有依賴的物件,用乙個虛擬的物件來建立以便於測試.假設你正在開發的的 中使用到了公司其他部門的介面 通過rpc服務 當編寫單元測試的時候你可能為了不讓介面真的去呼叫rpc服務而mock乙個介面的物件,...

單元測試之模擬Mock

先看下面一段 public class dataservice idataservice public int getcount 其中有 getcount 方法是為獲取列表的 count,我們為這個方法寫單元測試 getcount 中獲取列表是呼叫了 idatarespository 中的 getl...

golang單元測試之mock

搞單元測試,如果碰到這些情況 1,乙個函式,內部包含了很多並且很深的呼叫,但是如果單單測這個函式,其實實現的功能很簡單。2,乙個函式,包含了其他還未實現的呼叫。3,函式內部對資料的要求極為苛刻。那麼這時候就可以考慮使用mock來處理。mock,簡而言之就是可以通過注入我們所期望返回的資料,或者我們所...