TestableMock 簡(jiǎn)介TestableMock 開(kāi)源地址: TestableMock 在 2020 年 12 月開(kāi)始開(kāi)源,出自阿里云云效團(tuán)隊(duì),主要想解決 Java 開(kāi)發(fā)者在日常單元測(cè)試中經(jīng)常遇到的痛點(diǎn):
它所承載的職責(zé)是 “讓Java沒(méi)有難測(cè)的方法”,換種思路寫(xiě)Mock,讓單元測(cè)試更簡(jiǎn)單,這也是 TestableMock 名字的來(lái)歷。 無(wú)需初始化,不挑測(cè)試框架,甭管要換的是私有方法、靜態(tài)方法、構(gòu)造方法還是其他任何類(lèi)的任何方法,也甭管要換的對(duì)象是怎么創(chuàng)建的。 寫(xiě)好 Mock 定義,加個(gè) @MockMethod 注解,一切統(tǒng)統(tǒng)搞定。 主流Mock工具對(duì)比在 TestableMock 開(kāi)源之前,目前市面上主流的 Mock 工具主要有:
Mockito 應(yīng)該是目前使用最多的 Mock 工具了,因?yàn)樗褂米銐蚝?jiǎn)單,在 IntelliJ IDEA 和 Eclipse 開(kāi)發(fā)工具上也都有專(zhuān)用的插件支持,但 Mock 功能相對(duì)來(lái)說(shuō)還是較弱,不能覆蓋所有應(yīng)用場(chǎng)景。因?yàn)槠涫褂玫氖莿?dòng)態(tài)代理技術(shù),我們都知道,動(dòng)態(tài)代理只能在方法前后環(huán)繞,有一定的局限性,所以 final 類(lèi)型、靜態(tài)方法、私有方法全都無(wú)法覆蓋到。 上面所列的主流的 Mock 工具也只有 PowerMock 在功能上能夠與 TestableMock 持平,但 PowerMock 使用較為復(fù)雜,而且由于使用的是自定義類(lèi)加載器技術(shù),所以也還會(huì)存在一定的問(wèn)題。 下面來(lái)看下具體對(duì)比:
TestableMock 和 JMockit 底層一致,使用的是 "運(yùn)行時(shí)字節(jié)碼修改" 技術(shù),在單元測(cè)試啟動(dòng)時(shí)就掃描測(cè)試類(lèi)和被測(cè)類(lèi)的字節(jié)碼,完成 Mock 方法的替換。 現(xiàn)在綜合看來(lái),阿里開(kāi)源的 TestableMock 是最牛逼的了,這是要干掉市面上所有 Mock 工具!另外,關(guān)注公眾號(hào)Java技術(shù)棧,在后臺(tái)回復(fù):工具,可以獲取我整理的 Java 開(kāi)發(fā)工具系列干貨,非常齊全。 上手 TestableMock在項(xiàng)目中的 pom.xml 文件中增加 testable 相關(guān)依賴(lài)及單元測(cè)試相關(guān)依賴(lài)和插件,完整的配置如下: <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> 這里棧長(zhǎng)以 Maven 為示例集成使用 TestableMock,Gradle 版本請(qǐng)參考官方文檔。另外,關(guān)注公眾號(hào)Java技術(shù)棧,在后臺(tái)回復(fù):Maven,可以獲取我整理的 Maven 系列教程,非常齊全。 增加一個(gè)類(lèi),調(diào)用任意方法、成員方法、靜態(tài)方法: /** * @from 公眾號(hào):Java技術(shù)棧 * @author 棧長(zhǎng) */ public class TestableMock { /** * 調(diào)用任意方法 */ public String commonMethod() { return " www ".trim() + "." + " javastack".substring(1) + "www.".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; } } 增加單元測(cè)試類(lèi): 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 棧長(zhǎng) * @from 公眾號(hào):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 "_"; } @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._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(); } } 在以上單元測(cè)試類(lèi)中,以 @MockMethod 注解標(biāo)識(shí)的方法都是 Mock 方法,Mock 了任意方法、成員方法、靜態(tài)方法。 使用確實(shí)很簡(jiǎn)單,非常靈活,功能也確實(shí)比動(dòng)態(tài)代理那種要強(qiáng)大,一個(gè) @MockMethod 注解走天下,可以扔掉其他的 Mock 工具了。 參考文檔:
|
|
來(lái)自: 新進(jìn)小設(shè)計(jì) > 《待分類(lèi)》