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


    最近栈长注意到阿里开源了自家的 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 工具了。

    参考文档:

    版权申明:本文系公众号 "Java技术栈" 原创,原创实属不易,转载、引用本文内容请注明出处,禁止抄袭、洗稿,请自重,尊重他人劳动成果和知识产权。

    近期热文推荐:

    1.Java 15 正式发布, 14 个新特性,刷新你的认知!!

    2.终于靠开源项目弄到 IntelliJ IDEA 激活码了,真香!

    3.我用 Java 8 写了一段逻辑,同事直呼看不懂,你试试看。。

    4.吊打 Tomcat ,Undertow 性能很炸!!

    5.《Java开发手册(嵩山版)》最新发布,速速下载!

    觉得不错,别忘了随手点赞+转发哦!

  • 相关阅读:
    浅谈对java中锁的理解
    Spring 4 支持的 Java 8 特性
    【转】Java线程面试题 Top 50
    JVM知识点总览-中高级Java工程师面试必备
    [LeetCode] 195. Tenth Line 第十行
    [LeetCode] 281. Zigzag Iterator 之字形迭代器
    [LeetCode] 324. Wiggle Sort II 摆动排序 II
    [LeetCode] 280. Wiggle Sort 摆动排序
    [LeetCode] 167. Fraction to Recurring Decimal 分数转循环小数
    [LeetCode] 187. Repeated DNA Sequences 求重复的DNA序列
  • 原文地址:https://www.cnblogs.com/javastack/p/14334476.html
Copyright © 2020-2023  润新知