阿里TestableMock正式开源,最容易上手的 Mock 工具!

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

最近栈长注意到阿里开源了自家的 Mock 工具:TestableMock,该工具号称最轻量、简单、舒适的 Mock 测试工具,功能十分强大,媲美 PowerMock,用法比 Mockito 还要简洁,还不挑框架,指哪换哪,一个 @MockMethod 注解打天下。。。

这么强大的么?栈长赶紧来体验一翻!

TestableMock 简介

TestableMock 开源地址:

https://github.com/alibaba/testable-mock

阿里TestableMock正式开源,最容易上手的 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 相关依赖及单元测试相关依赖和插件,完整的配置如下:


  1. <properties>

  2.     <testable.version>0.4.9</testable.version>

  3.     <junit.version>5.6.2</junit.version>

  4. </properties>

  5. <dependencies>

  6.     <dependency>

  7.         <groupId>com.alibaba.testable</groupId>

  8.         <artifactId>testable-all</artifactId>

  9.         <version>${testable.version}</version>

  10.         <scope>test</scope>

  11.     </dependency>

  12.     <dependency>

  13.         <groupId>org.junit.jupiter</groupId>

  14.         <artifactId>junit-jupiter-api</artifactId>

  15.         <version>${junit.version}</version>

  16.         <scope>test</scope>

  17.     </dependency>

  18. </dependencies>

  19. <build>

  20.     <plugins>

  21.         <plugin>

  22.             <groupId>org.apache.maven.plugins</groupId>

  23.             <artifactId>maven-surefire-plugin</artifactId>

  24.             <configuration>

  25.                 <argLine>-javaagent:${settings.localRepository}/com/alibaba/testable/testable-agent/${testable.version}/testable-agent-${testable.version}.jar</argLine>

  26.             </configuration>

  27.         </plugin>

  28.     </plugins>

  29. </build>

这里栈长以 Maven 为示例集成使用 TestableMock,Gradle 版本请参考官方文档。另外,关注公众号Java技术栈,在后台回复:Maven,可以获取我整理的 Maven 系列教程,非常齐全。

增加一个类,调用任意方法、成员方法、静态方法:


  1. /**

  2.  * @from 公众号:Java技术栈

  3.  * @author 栈长

  4.  */

  5. public class TestableMock {

  6.     /**

  7.      * 调用任意方法

  8.      */

  9.     public String commonMethod() {

  10.         return " www ".trim() + "." + " javastack".substring(1) + "www.javastack.cn".startsWith(".com");

  11.     }

  12.     /**

  13.      * 调用成员、静态方法

  14.      */

  15.     public String memberMethod(String s) {

  16.         return "{ \"result\": \"" + innerMethod(s) + staticMethod() + "\"}";

  17.     }

  18.     private static String staticMethod() {

  19.         return "WWW_JAVASTACK_CN";

  20.     }

  21.     private String innerMethod(String website) {

  22.         return "our website is: " + website;

  23.     }

  24. }

增加单元测试类:


  1. import com.alibaba.testable.core.annotation.MockMethod;

  2. import org.junit.jupiter.api.Test;

  3. import static com.alibaba.testable.core.matcher.InvokeVerifier.verify;

  4. import static org.junit.jupiter.api.Assertions.assertEquals;

  5. /**

  6.  * @author 栈长

  7.  * @from 公众号:Java技术栈

  8.  */

  9. class TestableMockTest {

  10.     private TestableMock testableMock = new TestableMock();

  11.     /**

  12.      * Mock 任意方法

  13.      * @return

  14.      */

  15.     @MockMethod(targetClass = String.class)

  16.     private String trim() {

  17.         return "http://www";

  18.     }

  19.     @MockMethod(targetClass = String.class, targetMethod = "substring")

  20.     private String substr(int i) {

  21.         return "javastack.cn_";

  22.     }

  23.     @MockMethod(targetClass = String.class)

  24.     private boolean startsWith(String website) {

  25.         return false;

  26.     }

  27.     /**

  28.      * Mock 成员方法

  29.      * @param text

  30.      * @return

  31.      */

  32.     @MockMethod(targetClass = TestableMock.class)

  33.     private String innerMethod(String text) {

  34.         return "mock_" + text;

  35.     }

  36.     /**

  37.      * Mock 静态方法

  38.      * @return

  39.      */

  40.     @MockMethod(targetClass = TestableMock.class)

  41.     private String staticMethod() {

  42.         return "_MOCK_JAVASTACK";

  43.     }

  44.     @Test

  45.     void commonMethodTest() {

  46.         assertEquals("http://www.javastack.cn_false", testableMock.commonMethod());

  47.         verify("trim").withTimes(1);

  48.         verify("substr").withTimes(1);

  49.         verify("startsWith").withTimes(1);

  50.     }

  51.     @Test

  52.     void memberMethodTest() {

  53.         assertEquals("{ \"result\": \"mock_hello_MOCK_JAVASTACK\"}", testableMock.memberMethod("hello"));

  54.         verify("innerMethod").withTimes(1);

  55.         verify("staticMethod").withTimes(1);

  56.         verify("innerMethod").with("hello");

  57.         verify("staticMethod").with();

  58.     }

  59.     

  60. }

在以上单元测试类中,以  @MockMethod 注解标识的方法都是 Mock 方法,Mock 了任意方法、成员方法、静态方法。

使用确实很简单,非常灵活,功能也确实比动态代理那种要强大,一个 @MockMethod 注解走天下,可以扔掉其他的 Mock 工具了。

参考文档:

  • https://github.com/alibaba/testable-mock

  • https://alibaba.github.io/testable-mock/

     

上一篇:springboot项目单元测试使用PowerMockito跳过静态方法


下一篇:计算机毕业设计Java化妆品销售网站