關於單測技術選型,聊聊我的思考
對於單測來說,目前常用的單測框架有:
JUnit Mockito Spock PowerMock JMockit TestableMock
其中 JUnit 不支援 Mock,因此基本不會只用 JUnit,而是結合其他有 Mock 功能的框架一起使用。從知名度及使用率來說,Mockito 和 Spock 使用較多,而 PowerMock、JMockit、TestableMock 使用較少。下面我們將主要對比 Mockito 和 Spock 兩種框架的差異。
Mockito
Mockito 是 Java 單元測試中的 Mock 框架,一般都是與 JUnit 一起使用。Mockito 功能強大,幾乎所有你能想到的功能都支援,並且由於釋出時間較長,因此使用的人非常多。
優點:功能強大、使用人數多、資料豐富。 缺點:程式碼不夠簡潔、沒有統一的單測結構、不支援靜態方法和私有方法 Mock。
更多資訊詳見官網:
Spock
Spock 是一個企業級的測試規範框架,可用來測試 Java 和 Groovy 應用。Spock 最大的特色是其簡潔美觀的語言規範。Spock 相容絕大多數 IDE、編譯工具和 CI 整合伺服器。Spock 框架使用 Groovy 語言編寫,而 Groovy 語言則是 Java 語言的超集,絕大多數 Java 語言語法在 Groovy 中都支援。
優點:單測結構統一、程式碼簡潔、異常測試及引數測試支援更好。 缺點:學習成本略高、不支援靜態方法和私有方法 Mock。
更多資訊詳見官網:
Mockito vs Spock
在 Spock vs JUnit 5 - the ultimate feature comparison 中詳細對比了 Mokito 與 Spock 的差異,他們在發展情況、學習曲線、工具支援等方面的比較如下圖所示。
從上圖可以看到,Mockito 框架在發展、學習曲線、工具支援、從 JUnit4 遷移幾方面比較有優勢。而 Spock 框架則在測試結構、異常測試、條件測試等方面比較有優勢。因此,選擇哪個測試框架完全基於實際情況。例如,如果你目前的情況是:
Java 是唯一的語言。 想要更強的編譯時錯誤檢查。 更穩定、更主流的實現方式。
那麼選擇 JUnit + Mockito 的方式是更好的選擇。但如果你目前的情況是:
希望單測跟簡單易讀 更簡潔的引數測試與異常測試
那麼選擇 Spock 會是更好的選擇。
為啥選擇 Spock?
根據前面的分析,Mockito 的主要優勢在於比較穩定、主流,缺點在於不夠簡潔易讀。而 Spock 雖然使用人群沒有 Mockito 那麼多,但國內也有一些大廠在使用 Spock,例如美團等(可參考:Spock 單元測試框架介紹以及在美團優選的實踐)。
我們重視寫單測,但是又不希望寫單測花費太多時間,畢竟業務才是第一位的。因此,我們希望單測程式碼儘可能簡潔、可維護。 基於這個原因,我們選擇了 Spock 框架作為朝昔後端的單測框架解決方案。而 Spock 不支援 static 方法及 private 方法 Mock 的缺陷,則嘗試透過整合 PowerMock 或 TestableMock 來解決。
可維護性更強
在極客時間《程式設計師的測試課》中,有一節關於講了一個好的自動化測試長什麼樣?在這裡面,作者提到一個好的單測應該由 準備、執行、斷言、清理
4 個階段組成。
對於 Mockito 而言,它並沒有規定具體的程式碼規範,因此只能依靠註釋來標註哪些程式碼是準備階段的程式碼,哪些是執行階段的程式碼,哪些是斷言階段的程式碼,如下程式碼所示。
class SimpleCalculatorTest {
@Test
void shouldAddTwoNumbers() {
//given 準備
Calculator calculator = new Calculator();
//when 執行
int result = calculator.add(1, 2);
//then 斷言
assertEquals(3, result);
}
}
對於 Spock 而言,其透過 given-when-then 的結構,強制要求編寫者將不同階段的程式碼放到不同的位置,從而增強了可讀性。同樣是用於測試計算器的加法函式的單測用例,使用 Spock 框架編寫的單測如下程式碼所示。
class SimpleCalculatorSpec extends Specification {
def "should add two numbers"() {
given: "create a calculater instance"
Calculator calculator = new Calculator()
when: "get calculating result via the calculater"
int result = calculator.add(1, 2)
then: "assert the result is right"
result == 3
}
}
可以看到,透過 given-when-then
結構的劃分,我們可以更加快速地弄清楚單測的內容,從而提高單測的可讀性,使得單測更加容易維護。
程式碼更加簡潔
對於 Mockito 與 Spock 而言,它們之間的一個很大的差別是:Spock 的程式碼更加簡潔。這個特性可以讓我們編寫比 Mockito 更少的程式碼,從而實現同樣的功能。例如在 Mockito 中,我們 Mock 某個介面實現時,通常需要寫一長串的 give(...).return(...)
程式碼。而在進行斷言的時候,也需要寫比較長的 then(xx).should(xx).checkxx()
程式碼,如下圖所示。
@Test
public void should_not_call_remote_service_if_found_in_cache() {
//given
given(cacheMock.getCachedOperator(CACHED_MOBILE_NUMBER)).willReturn(Optional.of(PLUS));
//when
service.checkOperator(CACHED_MOBILE_NUMBER);
//then
then(webserviceMock).should(never()).checkOperator(CACHED_MOBILE_NUMBER);
verify(webserviceMock, never()).checkOperator(CACHED_MOBILE_NUMBER);
}
但在 Spock 中的程式碼就相對比較簡潔,如下所示程式碼實現了上述 Mockito 程式碼同樣的功能。
def "should not hit remote service if found in cache"() {
given:
cacheMock.getCachedOperator(CACHED_MOBILE_NUMBER) >> Optional.of(PLUS)
when:
service.checkOperator(CACHED_MOBILE_NUMBER)
then:
0 * webserviceMock.checkOperator(CACHED_MOBILE_NUMBER)
}
可以看到,Spock 沒有 given、willReturn 等關鍵詞,而是取而用 >> 等符號來實現,這樣程式碼更加簡潔,閱讀起來也更加明瞭。
案例程式碼對比:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024923/viewspace-2944985/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 關於技術的選型
- 聊聊技術選型
- 技術選型的一點個人思考
- 聊聊創業公司的技術選型--樸素的技術觀創業
- 前端技術選型及背後思考前端
- 資料產品的前端技術選型的思考前端
- 關於遊戲技術美術工程師的思考遊戲工程師
- 關於大資料技術的一點思考大資料
- 技術選型的藝術
- 關於向量瓦片技術支援前端渲染帶來的思考前端
- 關於技術書籍,我是這麼來選書和看書的
- 關於前端技術寫作✒,我想要說的?前端
- 關於 PHP 框架的簡單思考PHP框架
- 關於技術人員自身能力提升的一些思考
- 選單技術
- 技術選型指南
- Blog 技術選型
- 關於IT,關於技術
- 我用ChatGPT做直播技術選型,卷死了同事ChatGPT
- 關於 Angular HttpClient 的單例特性的思考AngularHTTPclient單例
- 技術選型的藝術---湖北技術價值分享會
- 百度Java架構師分享分散式鎖的技術選型及思考Java架構分散式
- 關於MQ的幾件小事(一)訊息佇列的用途、優缺點、技術選型MQ佇列
- 關於我對Spring迴圈依賴的思考Spring
- 我的技術書單 [Hex Note]
- 聊聊測試開發中提升 level 一些關鍵技術
- 開源技術夠用了麼?我的 NAS 選型與搭建過程
- 技術演技的思考
- 十問分散式資料庫:技術趨勢、選型及標準思考分散式資料庫
- SpringCloud微服務技術選型SpringGCCloud微服務
- 關於技術文件
- 關於技術方案
- 我對測試的思考
- Redux 的困擾與如何技術選型Redux
- Flutter UI自動化測試技術方案選型與探索FlutterUI
- 技術選型之Docker容器引擎Docker
- 應用監控的選型思考
- 2020年一定要關注的技術趨勢和選型建議