1. 程式人生 > >走進Java介面測試之Mock(概念篇)

走進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 的方案各有各的便利性,看起來都是對介面的模擬。