最近堆疊長注意到阿里開源了自家的 Mock 工具:TestableMock,該工具號稱最輕量、簡單、舒適的 Mock 測驗工具,功能十分強大,媲美 PowerMock,用法比 Mockito 還要簡潔,還不挑框架,指哪換哪,一個 @MockMethod 注解打天下,,,
這么強大的么?堆疊長趕緊來體驗一翻!
TestableMock 簡介
TestableMock 開源地址:
https://github.com/alibaba/testable-mock

TestableMock 在 2020 年 12 月開始開源,出自阿里云云效團隊,主要想解決 Java 開發者在日常單元測驗中經常遇到的痛點:
- 外部依賴Mock繁瑣
- 私有方法難測驗
- 無回傳值方法難測驗
- 復雜引數難構造
它所承載的職責是 “讓Java沒有難測的方法”,換種思路寫Mock,讓單元測驗更簡單,這也是 TestableMock 名字的來歷,
無需初始化,不挑測驗框架,甭管要換的是私有方法、靜態方法、構造方法還是其他任何類的任何方法,也甭管要換的物件是怎么創建的,
寫好 Mock 定義,加個 @MockMethod 注解,一切統統搞定,
主流Mock工具對比
在 TestableMock 開源之前,目前市面上主流的 Mock 工具主要有:
- Mockito
- Spock
- PowerMock
- JMockit
- EasyMock
- ....
Mockito 應該是目前使用最多的 Mock 工具了,因為它使用足夠簡單,在 IntelliJ IDEA 和 Eclipse 開發工具上也都有專用的插件支持,但 Mock 功能相對來說還是較弱,不能覆寫所有應用場景,因為其使用的是動態代理技術,我們都知道,動態代理只能在方法前后環繞,有一定的局限性,所以 final 型別、靜態方法、私有方法全都無法覆寫到,
上面所列的主流的 Mock 工具也只有 PowerMock 在功能上能夠與 TestableMock 持平,但 PowerMock 使用較為復雜,而且由于使用的是自定義類加載器技術,所以也還會存在一定的問題,
下面來看下具體對比:
| 工具 | 原理 | 最小Mock單元 | 被Mock方法限制 | 難度 | IDE支持 |
|---|---|---|---|---|---|
| Mockito | 動態代理 | 類 | 不能Mock私有/靜態和構造方法 | 較容易 | 很好 |
| Spock | 動態代理 | 類 | 不能Mock私有/靜態和構造方法 | 較復雜 | 一般 |
| PowerMock | 自定義類加載器 | 類 | 任何方法皆可 | 較復雜 | 較好 |
| JMockit | 運行時位元組碼修改 | 類 | 不能Mock構造方法 | 較復雜 | 一般 |
| TestableMock | 運行時位元組碼修改 | 方法 | 任何方法皆可 | 很容易 | 一般 |
TestableMock 和 JMockit 底層一致,使用的是 "運行時位元組碼修改" 技術,在單元測驗啟動時就掃描測驗類和被測類的位元組碼,完成 Mock 方法的替換,
現在綜合看來,阿里開源的 TestableMock 是最牛逼的了,這是要干掉市面上所有 Mock 工具!另外,關注公眾號Java技術堆疊,在后臺回復:工具,可以獲取我整理的 Java 開發工具系列干貨,非常齊全,
上手 TestableMock
在專案中的 pom.xml 檔案中增加 testable 相關依賴及單元測驗相關依賴和插件,完整的配置如下:
<properties>
<testable.version>0.4.9</testable.version>
<junit.version>5.6.2</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba.testable</groupId>
<artifactId>testable-all</artifactId>
<version>${testable.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-javaagent:${settings.localRepository}/com/alibaba/testable/testable-agent/${testable.version}/testable-agent-${testable.version}.jar</argLine>
</configuration>
</plugin>
</plugins>
</build>
這里堆疊長以 Maven 為示例集成使用 TestableMock,Gradle 版本請參考官方檔案,另外,關注公眾號Java技術堆疊,在后臺回復:Maven,可以獲取我整理的 Maven 系列教程,非常齊全,
增加一個類,呼叫任意方法、成員方法、靜態方法:
/**
* @from 公眾號:Java技術堆疊
* @author 堆疊長
*/
public class TestableMock {
/**
* 呼叫任意方法
*/
public String commonMethod() {
return " www ".trim() + "." + " javastack".substring(1) + "www.javastack.cn".startsWith(".com");
}
/**
* 呼叫成員、靜態方法
*/
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技術堆疊
*/
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 靜態方法
* @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 注解標識的方法都是 Mock 方法,Mock 了任意方法、成員方法、靜態方法,
使用確實很簡單,非常靈活,功能也確實比動態代理那種要強大,一個 @MockMethod 注解走天下,可以扔掉其他的 Mock 工具了,
參考檔案:
- https://github.com/alibaba/testable-mock
- https://alibaba.github.io/testable-mock/
著作權申明:本文系公眾號 "Java技術堆疊" 原創,原創實屬不易,轉載、參考本文內容請注明出處,禁止抄襲、洗稿,請自重,尊重他人勞動成果和知識產權,
近期熱文推薦:
1.Java 15 正式發布, 14 個新特性,重繪你的認知!!
2.終于靠開源專案弄到 IntelliJ IDEA 激活碼了,真香!
3.我用 Java 8 寫了一段邏輯,同事直呼看不懂,你試試看,,
4.吊打 Tomcat ,Undertow 性能很炸!!
5.《Java開發手冊(嵩山版)》最新發布,速速下載!
覺得不錯,別忘了隨手點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/253369.html
標籤:Java
