阿里 Mock 工具正式開源,干掉市面上所有 Mock 工具!

Java技術(shù)棧
www.javastack.cn
關(guān)注閱讀更多優(yōu)質(zhì)文章
最近棧長注意到阿里開源了自家的 Mock 工具:TestableMock,該工具號稱最輕量、簡單、舒適的 Mock 測試工具,功能十分強大,媲美 PowerMock,用法比 Mockito 還要簡潔,還不挑框架,指哪換哪,一個 @MockMethod 注解打天下。。。
這么強大的么?棧長趕緊來體驗一翻!
TestableMock 簡介
TestableMock 開源地址:
https://github.com/alibaba/testable-mock

TestableMock 在 2020 年 12 月開始開源,出自阿里云云效團隊,主要想解決 Java 開發(fā)者在日常單元測試中經(jīng)常遇到的痛點:
外部依賴Mock繁瑣 私有方法難測試 無返回值方法難測試 復(fù)雜參數(shù)難構(gòu)造
它所承載的職責(zé)是 “讓Java沒有難測的方法”,換種思路寫Mock,讓單元測試更簡單,這也是 TestableMock 名字的來歷。
無需初始化,不挑測試框架,甭管要換的是私有方法、靜態(tài)方法、構(gòu)造方法還是其他任何類的任何方法,也甭管要換的對象是怎么創(chuàng)建的。
寫好 Mock 定義,加個 @MockMethod 注解,一切統(tǒng)統(tǒng)搞定。
主流Mock工具對比
在 TestableMock 開源之前,目前市面上主流的 Mock 工具主要有:
Mockito Spock PowerMock JMockit EasyMock ....
Mockito 應(yīng)該是目前使用最多的 Mock 工具了,因為它使用足夠簡單,在 IntelliJ IDEA 和 Eclipse 開發(fā)工具上也都有專用的插件支持,但 Mock 功能相對來說還是較弱,不能覆蓋所有應(yīng)用場景。因為其使用的是動態(tài)代理技術(shù),我們都知道,動態(tài)代理只能在方法前后環(huán)繞,有一定的局限性,所以 final 類型、靜態(tài)方法、私有方法全都無法覆蓋到。
上面所列的主流的 Mock 工具也只有 PowerMock 在功能上能夠與 TestableMock 持平,但 PowerMock 使用較為復(fù)雜,而且由于使用的是自定義類加載器技術(shù),所以也還會存在一定的問題。
下面來看下具體對比:
| 工具 | 原理 | 最小Mock單元 | 被Mock方法限制 | 難度 | IDE支持 |
|---|---|---|---|---|---|
| Mockito | 動態(tài)代理 | 類 | 不能Mock私有/靜態(tài)和構(gòu)造方法 | 較容易 | 很好 |
| Spock | 動態(tài)代理 | 類 | 不能Mock私有/靜態(tài)和構(gòu)造方法 | 較復(fù)雜 | 一般 |
| PowerMock | 自定義類加載器 | 類 | 任何方法皆可 | 較復(fù)雜 | 較好 |
| JMockit | 運行時字節(jié)碼修改 | 類 | 不能Mock構(gòu)造方法 | 較復(fù)雜 | 一般 |
| TestableMock | 運行時字節(jié)碼修改 | 方法 | 任何方法皆可 | 很容易 | 一般 |
TestableMock 和 JMockit 底層一致,使用的是 "運行時字節(jié)碼修改" 技術(shù),在單元測試啟動時就掃描測試類和被測類的字節(jié)碼,完成 Mock 方法的替換。
現(xiàn)在綜合看來,阿里開源的 TestableMock 是最牛逼的了,這是要干掉市面上所有 Mock 工具!另外,關(guān)注公眾號Java技術(shù)棧,在后臺回復(fù):工具,可以獲取我整理的 Java 開發(fā)工具系列干貨,非常齊全。
上手 TestableMock
在項目中的 pom.xml 文件中增加 testable 相關(guān)依賴及單元測試相關(guān)依賴和插件,完整的配置如下:
????0.4.9
????5.6.2
????
????????com.alibaba.testable
????????testable-all
????????${testable.version}
????????test
????
????
????????org.junit.jupiter
????????junit-jupiter-api
????????${junit.version}
????????test
????
????
????????
????????????org.apache.maven.plugins
????????????maven-surefire-plugin
????????????
????????????????-javaagent:${settings.localRepository}/com/alibaba/testable/testable-agent/${testable.version}/testable-agent-${testable.version}.jar
????????????
????????
????
這里棧長以 Maven 為示例集成使用 TestableMock,Gradle 版本請參考官方文檔。另外,關(guān)注公眾號Java技術(shù)棧,在后臺回復(fù):Maven,可以獲取我整理的 Maven 系列教程,非常齊全。
增加一個類,調(diào)用任意方法、成員方法、靜態(tài)方法:
/**
?*?@from 公眾號:Java技術(shù)棧
?*?@author?棧長
?*/
public?class?TestableMock?{
????/**
?????*?調(diào)用任意方法
?????*/
????public?String?commonMethod()?{
????????return?"?www?".trim()?+?"."?+?"?javastack".substring(1)?+?"www.javastack.cn".startsWith(".com");
????}
????/**
?????*?調(diào)用成員、靜態(tài)方法
?????*/
????public?String?memberMethod(String?s)?{
????????return?"{?\"result\":?\""?+?innerMethod(s)?+?staticMethod()?+?"\"}";
????}
????private?static?String?staticMethod()?{
????????return?"WWW_JAVASTACK_CN";
????}
????private?String?innerMethod(String?website)?{
????????return?"our?website?is:?"?+?website;
????}
}
增加單元測試類:
import?com.alibaba.testable.core.annotation.MockMethod;
import?org.junit.jupiter.api.Test;
import?static?com.alibaba.testable.core.matcher.InvokeVerifier.verify;
import?static?org.junit.jupiter.api.Assertions.assertEquals;
/**
?*?@author?棧長
?*?@from 公眾號:Java技術(shù)棧
?*/
class?TestableMockTest?{
????private?TestableMock?testableMock?=?new?TestableMock();
????/**
?????*?Mock?任意方法
?????*?@return
?????*/
????@MockMethod(targetClass?=?String.class)
????private?String?trim()?{
????????return?"http://www";
????}
????@MockMethod(targetClass?=?String.class,?targetMethod?=?"substring")
????private?String?substr(int?i)?{
????????return?"javastack.cn_";
????}
????@MockMethod(targetClass?=?String.class)
????private?boolean?startsWith(String?website)?{
????????return?false;
????}
????/**
?????*?Mock?成員方法
?????*?@param?text
?????*?@return
?????*/
????@MockMethod(targetClass?=?TestableMock.class)
????private?String?innerMethod(String?text)?{
????????return?"mock_"?+?text;
????}
????/**
?????*?Mock?靜態(tài)方法
?????*?@return
?????*/
????@MockMethod(targetClass?=?TestableMock.class)
????private?String?staticMethod()?{
????????return?"_MOCK_JAVASTACK";
????}
????@Test
????void?commonMethodTest()?{
????????assertEquals("http://www.javastack.cn_false",?testableMock.commonMethod());
????????verify("trim").withTimes(1);
????????verify("substr").withTimes(1);
????????verify("startsWith").withTimes(1);
????}
????@Test
????void?memberMethodTest()?{
????????assertEquals("{?\"result\":?\"mock_hello_MOCK_JAVASTACK\"}",?testableMock.memberMethod("hello"));
????????verify("innerMethod").withTimes(1);
????????verify("staticMethod").withTimes(1);
????????verify("innerMethod").with("hello");
????????verify("staticMethod").with();
????}
????
}
在以上單元測試類中,以 ?@MockMethod 注解標(biāo)識的方法都是 Mock 方法,Mock 了任意方法、成員方法、靜態(tài)方法。
使用確實很簡單,非常靈活,功能也確實比動態(tài)代理那種要強大,一個 @MockMethod 注解走天下,可以扔掉其他的 Mock 工具了。
參考文檔:
https://github.com/alibaba/testable-mock https://alibaba.github.io/testable-mock/
版權(quán)申明:本文系公眾號 "Java技術(shù)棧" 原創(chuàng),原創(chuàng)實屬不易,轉(zhuǎn)載、引用本文內(nèi)容請注明出處,禁止抄襲、洗稿,請自重,尊重他人勞動成果和知識產(chǎn)權(quán)。






關(guān)注Java技術(shù)??锤喔韶?/strong>


