走進Java接口測試之Mock(概念篇)

引言

實際工作中,測試人員可能會遇到如下情況:

  • 場景一:依賴接口不通,甲開發A模塊,乙開發B模塊,甲的進度比乙快,但A模塊的方法依賴於B模塊,要測試A模塊接口怎麼辦?
  • 場景二:異常數據難模擬,當需要測試接口一些異常數據,接口正常情況是否無法提供異常數據的。那麼如何簡便地構造接口的異常數據?
  • 場景三:依賴接口性能參數無法保障。在對接口性能壓測的時候,需要下游接口及時返回數據,滿足上游接口的調用頻度。在依賴接口多的情況下,如何減輕工作量?

Mock 的定義

性能基礎之淺談常見接口性能壓測文中,我們有簡單介紹過 Mock ,本文將詳細闡述 Mock 概念。
在接口測試過程中,對於某些不容易構造或者不容易獲取的對象,我們常常會用一個虛擬的對象代替以便測試。在具體的測試過程中,我們經常會碰到需要模擬數據或者接口的情況,因爲環境問題或者系統複雜度的問題,我們需要使用 Mock 方式進行數據的模擬。
引用淘寶網《接口測試白皮書》中的對 Mock 的定義:

Mock 是指使用各種技術手段模擬出各種需要的資源以供測試使用。
被 Mock 的資源通常有以下特徵:

  • 被測目標依賴該資源
  • 該資源可能因爲各種原因不穩定、返回結果不斷變化或者並不總是能夠獲取到
  • 該資源跟被測目標本身質量無關
  • 這些資源可能是一個外部或底層接口、一個系統、一組數據對象或者是一整套目標軟件的工作環境等。通過 Mock 避免對外部真實資源的依賴實現對被測目標的孤立測試,從而大大降低測試的難度,節約測試成本。
  • 需要注意的是利用 Mock 通過的測試與使用真實環境通過的測試畢竟還是有一定差別的。有些時候我們就是需要所測試的系統能夠處理依賴所產生的各種情況,包括正常情況和異常情況,我們同樣不能保證我們的Mock 可以模擬到每種這樣的情況。因此只在確實有必要的情況下才運用Mock。

Mock 的分類

目前主要應用兩大類 Mock 的場景。
一種是 Mock 一個對象,寫入一些預期的值,通過它進行自己想要的測試。主要適用於單元測試,哪種語言開發的程序必須用基於哪種語言的Mock 方案去實現。
例如:Mockito 只能針對 Java ,適用範圍:單測

另外一種就是 Mock 一個 Server ,構造一個假的服務返回預期的結果,也是爲了進行自己的測試。主要適用於接口&性能測試,Mock 方案和程序使用的語言無關,可以用 Java 實現,也可以用 Python 實現等,例如:搭建一個 Mock Server,適用範圍:無限制

這兩個場景構造了大部分的 Mock 使用範圍。

Mock 一個對象

此處使用Mockito示例

Mockito 是 GitHub 上使用最廣泛的 Mock 框架,並與 JUnit 結合使用。Mockito 框架可以創建和配置 mock 對象。使用 Mockito 簡化了具有外部依賴的類的測試開發。

在這裏插入圖片描述
一般使用 Mockito 的步驟:

  1. 模擬任何外部依賴並將這些模擬對象插入測試代碼中
  2. 執行測試中的代碼執行測試中的代碼
  3. 驗證代碼是否按照預期執行驗證代碼是否按照預期執行

引入pom

  <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-all</artifactId>
            <version>1.10.19</version>
        </dependency>
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>6.14.3</version>
        </dependency>

新建測試類,構造了 list 這樣的對象,並且給一個元素賦值 zuozewei。在最後斷言的時候,也可以通過這個 list 裏面確實有這個值。所以,通過這種方式,我們可以進行對象構造。可以是類,也可以是接口。
除了構造對象,當然也可以對方法設定的返回值指定異常。
上述代碼的意思就是當調用 list 的第二個元素的時候,拋出一個運行異常。

public class SimpleTest {

	@Test
	public void test(){
		// 創建Mock對象,參數可以是類或者接口
		List<String> list = mock(List.class);

		//設置方法的預期返回值
		when(list.get(0)).thenReturn("zuozewei");
		when(list.get(1)).thenThrow(new RuntimeException("test exception"));

		String result = list.get(0);

		//驗證方法調用
		verify(list).get(0);

		//斷言,list的第一個元素是否是"zuozwei"
		Assert.assertEquals(result,"zuozewei");

	}
}

上面只是列舉了 Mockito 的簡單用法。對於比較複雜的用法,大家可以通過官網深入學習。因爲 Mockito 主要用於單元測試,開發人員用的比較多,所以大家有興趣可以自行了解。

Mock Server

下圖很好的解釋了Mock Server 位置和作用:
在這裏插入圖片描述
常見的Mock Server

  1. WireMock,支持HTTP協議,參考:http://wiremock.org/
  2. SoapUI MockService 支持WebService,參考:https://www.soapui.org/
  3. Dubbo,需要自己實現
  4. 使用Web框架自己開發Mock Server系統,參考:http://www.testclass.net/interface/flask_mock/
  5. 在線 Mock Server 系統,參考:http://easy-mock.com/login
  6. 使用現成的 Mock Server 庫創建系統,參考:
    MockServer:https://github.com/jamesdbloom/mockserver
    Moco:https://github.com/dreamhead/moco
    兩個項目都不錯有Mock Server庫,GitHub上面的 Star 也差不多。

小結

本文分場景介紹了兩種 Mock 方式,對於Mock Server 的方案各有各的便利性,看起來都是對接口的模擬。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章