• Groovy动态添加方法和属性及Spock单测


    在最近的一边学习一边复习的过程中,发现了很多有意思的事情。今天就分享一个groovy.lang.MetaClass应用:如何运行中,动态给类和对象增加属性和添加方法。

    对于Java、Groovy来讲,如果用到一个类,那么这个类的属性和方法已经是固定的,可是随着我的学习,发现这个常识并不靠谱。下面开始我的表演。

    添加对象方法

    下面是简化的语法object.metaClass.object_method = {闭包},如下:

            def funTester = new FunTester()
            funTester.metaClass.test = {
                logger.info("我是测试方法:{}","test")
            }
            funTester.test()
    

    控制台输出:

    INFO-> main 当前用户:oker,工作目录:/Users/oker/IdeaProjects/funtester/,系统编码格式:UTF-8,系统Mac OS X版本:10.16
    INFO-> main 我是测试方法:test
    
    Process finished with exit code 0
    

    添加静态方法

    下面是简化的语法object.metaClass.static.object_method = {闭包},如下:

            def funTester = new FunTester()
            funTester.metaClass.test = {
                logger.info("我是测试方法:{}","static.test")
            }
            funTester.test()
    

    控制台输出:

    INFO-> main 当前用户:oker,工作目录:/Users/oker/IdeaProjects/funtester/,系统编码格式:UTF-8,系统Mac OS X版本:10.16
    INFO-> main 我是测试方法:static.test
    
    Process finished with exit code 0
    

    添加属性

            funTester.metaClass.setProperty("name","FunTester")
            logger.info(funTester.getProperty("name"))
    

    控制台输出:

    INFO-> main 当前用户:oker,工作目录:/Users/oker/IdeaProjects/funtester/,系统编码格式:UTF-8,系统Mac OS X版本:10.16
    INFO-> main FunTester
    
    Process finished with exit code 0
    
    

    FunTester类代码:

        private static class FunTester {
    
        }
    

    Spock单元测试

    下面使用Spock单元测试框架进行测试,有兴趣的可以看看之前的文章:

    代码如下:

    package com.funtest.spock
    
    
    import org.apache.logging.log4j.LogManager
    import org.apache.logging.log4j.Logger
    import spock.lang.Shared
    
    class Mop extends spock.lang.Specification {
    
        @Shared
        private static final Logger logger = LogManager.getLogger(Mop.class);
    
        def setup() {
            logger.info("测试方法开始了")
        }
    
        def cleanup() {
            logger.info("测试方法结束了")
        }
    
        def setupSpec() {
            fun.metaClass.getName() {
                def property = fun.getProperty("name")
                logger.warn("获取" + property)
                return property
            }
            fun.metaClass.setName = {x ->
                logger.warn("设置" + x)
                fun.metaClass.setProperty("name", x)
                return fun.getName()
            }
            logger.info("测试类[${getClass().getName()}]开始了")
        }
    
        def cleanupSpec() {
            logger.info("测试类[${getClass().getName()}]结束了")
        }
    
    
        @Shared
        def fun = new Mop()
    
        def "测试动态添加对象方法"() {
            given:
            fun.metaClass.ob_method = {return 12}
            expect:
            12 == fun.ob_method()
        }
    
    
        def "测试动态添加静态方法"() {
            given:
            Mop.metaClass.static.clas_method = {return 12}
            expect:
            12 == Mop.clas_method()
        }
    
        def "测试动态添加获取属性"() {
            expect:
            fun.setName(name) == tt
    
            where:
            name        | tt
            "FunTester" | "FunTester"
            "Have Fun"  | "Have Fun"
        }
    
    }
    
    
    

    控制台输出:

    
    > Task :test FAILED
    INFO-> Test worker 测试类[com.funtest.spock.Mop]开始了
    INFO-> Test worker 测试方法开始了
    INFO-> Test worker 测试方法结束了
    INFO-> Test worker 测试方法开始了
    INFO-> Test worker 测试方法结束了
    INFO-> Test worker 测试方法开始了
    WARN-> Test worker 设置FunTester
    WARN-> Test worker 获取FunTester
    INFO-> Test worker 测试方法结束了
    INFO-> Test worker 测试方法开始了
    WARN-> Test worker 设置Have Fun
    WARN-> Test worker 获取FunTester
    INFO-> Test worker 测试方法结束了
    
    Condition not satisfied:
    
    fun.setName(name) == tt
    |   |       |     |  |
    |   |       |     |  Have Fun
    |   |       |     false
    |   |       |     8 differences (11% similarity)
    |   |       |     (FunT)e(ster)
    |   |       |     (Hav-)e( Fun)
    |   |       Have Fun
    |   FunTester
    <com.funtest.spock.Mop@49013545 $spock_sharedField_fun=null specificationContext=org.spockframework.runtime.SpecificationContext@6c68765>
    
    	at com.funtest.spock.Mop.测试动态添加获取属性(Mop.groovy:60)
    
    
    INFO-> Test worker 测试类[com.funtest.spock.Mop]结束了
    
    Mop > 测试动态添加对象方法 PASSED
    Mop > 测试动态添加静态方法 PASSED
    Mop > 测试动态添加获取属性 > com.funtest.spock.Mop.测试动态添加获取属性 [name: FunTester, tt: FunTester, #0] PASSED
    Mop > 测试动态添加获取属性 > com.funtest.spock.Mop.测试动态添加获取属性 [name: Have Fun, tt: Have Fun, #1] FAILED
        org.spockframework.runtime.SpockComparisonFailure at Mop.groovy:60
    Mop > 测试动态添加获取属性 FAILED
    5 tests completed, 2 failed
    FAILURE: Build failed with an exception.
    4 actionable tasks: 1 executed, 3 up-to-date
    
    

    Have Fun ~ Tester !

  • 相关阅读:
    JVM系列六(自定义插入式注解器).
    JVM系列五(Javac 字节码编译器).
    2019 — 求不得,放不下
    Mybatis 条件判断单双引号解析问题
    JVM系列四(对象分配策略).
    JVM系列三(垃圾收集器).
    Spring MVC -- Spring Tool Suite和Maven(安装Tomcat、JDK)
    Spring MVC -- 单元测试和集成测试
    Spring MVC -- 下载文件
    Spring MVC -- 上传文件
  • 原文地址:https://www.cnblogs.com/FunTester/p/15437419.html
Copyright © 2020-2023  润新知