• groovy单测自动生成


    groovy单测自动生成

    以交易核心trade举例

    前置准备

    在这里插入图片描述

    注意:xxx.ftl需要放在测试resources的template下

    如果服务没有freemarker需要补充pom依赖

    <dependency>
    	<groupId>org.freemarkergroupId>
    	<artifactId>freemarkerartifactId>
    	<version>2.3.21version>
    	<scope>testscope>
    dependency>
    

    使用

    在这里插入图片描述

    将想要写的单测和自己的名字输入执行
    注意:如果是新服务导入需要对项目进行clean再编译,因为模板是读取target/test-classes/template/xxx.ftl

    结果

    单测地址已生成

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MlGvqcD9-1664281530881)(http://10.0.17.20/server/index.php?s=/api/attachment/visitFile/sign/9ebf247fce92dfc38b4d0c397588280c)]

    生成代码如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UmB4d93J-1664281530882)(http://10.0.17.20/server/index.php?s=/api/attachment/visitFile/sign/d04f2eaec610b943ec20cfce5877343e)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6EoQWTUR-1664281530883)(http://10.0.17.20/server/index.php?s=/api/attachment/visitFile/sign/0aba75336487cb7519f97faf7b52b5c8)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zd1bfeMB-1664281530884)(http://10.0.17.20/server/index.php?s=/api/attachment/visitFile/sign/db0431500331054abeb08f23f930d320)]

    代码及模板

    UnitTestGen.java

    /**
     * @ClassName UnitTestGen
     * @Descriptioin
     * @Author luoxiaoming
     * @Date 2022/9/27 15:16
     * @Version 1.0
     */
    
    
    public class UnitTestGen {
    
        public static void main(String[] args) throws Exception {
            //根据类生成单测模板
            UnitTestGen unitTestGen = new UnitTestGen();
            unitTestGen.genUnitTestByClass(CcbLoanApplyServiceImpl.class, "author", GROOVY);
        }
    
        //groovy通用单测
        public static final String GROOVY = "groovy";
        //支持静态方法的groovy通用单测
        public static final String STATIC_GROOVY = "staticGroovy";
        //基础mockito单测
        public static final String BASE_MOCKITO = "baseMockito";
        //支持静态方法mockito单测
        public static final String STATIC_MOCKITO = "staticMockito";
    
    
        private void genUnitTestByClass(Class classBean, String author, String unitTestType) throws Exception {
            //1. 创建FreeMarker的配置类
            Configuration cfg = new Configuration(Configuration.getVersion());
    
            //2. 指定模板加载器
    //        String templatePath = System.getProperty("user.dir")+"/trade/src/test/resources/";
            String templatePath = parsePath(this.getClass().getResource("/template").getPath() + "/");
            FileTemplateLoader fileTemplateLoader = new FileTemplateLoader(new File(templatePath));
            cfg.setTemplateLoader(fileTemplateLoader);
    
            //3. 获取模板
            Template template = getUnitTestType(cfg, unitTestType);
    
            //4. 构造数据模型
            Map<String, Object> map = packageMapRes(classBean, author, getServerName(templatePath), unitTestType);
    
            //5. 文件输出
            /**
             * 处理模型
             *      参数一 数据模型
             *      参数二 writer对象(FileWriter(文件输出),printWriter(控制台输出))
             */
            template.process(map, new OutputStreamWriter(new FileOutputStream(new File((String) map.get("unitTestOutPutLocation"))), "UTF-8"));
    //        template.process(map, new PrintWriter(System.out));
            System.out.println(String.format("单测地址-->%s", (String) map.get("unitTestOutPutLocation")));
    
        }
    
        /**
         * 获取对应的单测模板
         *
         * @param unitTestType
         * @return
         */
        private Template getUnitTestType(Configuration cfg, String unitTestType) throws IOException {
            Template template;
            switch (unitTestType) {
                case GROOVY:
                    template = cfg.getTemplate("GroovyUnitTestGen.ftl");
                    break;
                case STATIC_GROOVY:
                    template = cfg.getTemplate("StaticGroovyUnitTestGen.ftl");
                    break;
                case BASE_MOCKITO:
                    template = cfg.getTemplate("BaseMockitoUnitTestGen.ftl");
                    break;
                case STATIC_MOCKITO:
                    template = cfg.getTemplate("StaticMockitoUnitTestGen.ftl");
                    break;
                default:
                    throw new IllegalStateException("Unexpected value: " + unitTestType);
            }
            return template;
        }
    
        /**
         * 比如 \E:\code\phoenix-trade\trade\target\test-classes\template\ 获取 trade
         *
         * @param templatePath
         * @return
         */
        private String getServerName(String templatePath) {
            String serverName = "";
            String[] split = templatePath.split("\\\\");
            for (int i = 0; i < split.length; i++) {
                if (split[i].equals("target")) {
                    serverName = split[i - 1];
                }
            }
            return serverName;
        }
    
        private static Map<String, Object> packageMapRes(Class classObject, String author, String serverName, String unitTestType) {
            Map<String, Object> map = new HashMap<>();
            String simpleName = classObject.getSimpleName();
            StringBuffer sbName = new StringBuffer();
            sbName.append(simpleName.substring(0, 1).toLowerCase()).append(simpleName.substring(1));
    
            List<String> methodNameList = new ArrayList<>();
            //获取所有的setField 和 getField
            List<String> filterMethod = getfilterMethod(classObject);
            //过滤关键字 只要public
            Arrays.stream(classObject.getDeclaredMethods()).filter(t -> t.getModifiers() == 1 && !filterMethod.contains(t.getName())).forEach(method -> methodNameList.add(method.getName()));
    
            //import
            List<String> importList = new ArrayList<>();
            importList.add(classObject.getName());
            List<AutoWireService> autowireSeviceList = new ArrayList<>();
            //过滤只要private
            Arrays.stream(classObject.getDeclaredFields()).filter(t -> t.getModifiers() == 2).forEach(field -> {
                UnitTestGen unitTestGen = new UnitTestGen();
                AutoWireService autoWireService = unitTestGen.new AutoWireService();
                autoWireService.setUseService(field.getName());
                String[] sp = field.getType().getName().split("\\.");
                autoWireService.setMockService(sp[sp.length - 1]);
                autowireSeviceList.add(autoWireService);
    
                //导包
                importList.add(field.getType().getName());
            });
    
    
            map.put("className", simpleName);
            map.put("classShortName", sbName.toString());
            map.put("date", DateTools.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
            map.put("author", Optional.ofNullable(author).orElse("system"));
            map.put("package", classObject.getPackage());
            map.put("serviceList", autowireSeviceList);
            map.put("methodNameList", methodNameList);
            map.put("importList", importList);
    
            //获取输出地址
            StringBuffer sb = new StringBuffer(System.getProperty("user.dir"));
            sb.append("/").append(serverName).append("/src/test/java/").append(classObject.getPackage().getName().replaceAll("\\.", "\\/")).append("/");
            //若目录不存在创建目录
            File filePath = new File(sb.toString());
            if (!filePath.exists()) {
                filePath.mkdirs();
            }
            sb.append(simpleName).append("Test");
            if (GROOVY.equals(unitTestType) || STATIC_GROOVY.equals(unitTestType)) {
                sb.append(".groovy");
            } else {
                sb.append(".java");
            }
            map.put("unitTestOutPutLocation", parsePath(sb.toString()));
    
            return map;
        }
    
        @Data
        public class AutoWireService {
            String useService;
            String mockService;
        }
    
        private static List<String> getfilterMethod(Class classObject) {
            List<String> filterMethod = new ArrayList<>();
            Arrays.stream(classObject.getDeclaredFields()).forEach(t -> {
                StringBuffer setSb = new StringBuffer();
                setSb.append("set");
                setSb.append(t.getName().substring(0, 1).toUpperCase());
                setSb.append(t.getName().substring(1));
                filterMethod.add(setSb.toString());
                StringBuffer getSb = new StringBuffer();
                getSb.append("get");
                getSb.append(t.getName().substring(0, 1).toUpperCase());
                getSb.append(t.getName().substring(1));
                filterMethod.add(getSb.toString());
            });
            return filterMethod;
        }
    
        private static String parsePath(String path) {
            if (PlatformUtil.isWindows()) {
                return path.replaceAll("/+|\\\\+", "\\\\");
            } else {
                return path.replaceAll("/+|\\\\+", "/");
            }
        }
    
    
    }
    
    

    GroovyUnitTestGen.ftl

    ${package}
    
    import org.springframework.beans.factory.annotation.Autowired
    import spock.lang.Subject
    import spock.lang.Unroll
    import com.jdh.boot.util.SpringContextUtil
    <#list importList as import>
    import ${import}
    
    
    
    
    /**
    * 需要在原来的Service上暴露对应属性set方法-@Setter
    * @Descriptioin
    * @Author ${author}
    * @Date ${date}
    */
    @Subject(${className}.class)
    class ${className}Test extends SpockBaseRunner {
    
        @Autowired
        private ${className} ${classShortName}
    
    <#list serviceList as service>
        def ${service.useService} = Mock(${service.mockService})
    
    
        @Override
        def init() {
        <#list serviceList as service>
            ${classShortName}.${service.useService} = ${service.useService}
        
        }
    
        @Override
        def clean() {
        <#list serviceList as service>
            ${classShortName}.${service.useService} = SpringContextUtil.getObject(${service.mockService}.class)
        
        }
    
        <#list methodNameList as methodName>
        @Unroll
        def "${className}-${methodName}"() {
            given:
    
            when:
            ${classShortName}.${methodName}()
            then:
    
            where:
         }
    
        
    
    }
    

    StaticGroovyUnitTestGen.ftl

    ${package}
    
    import org.junit.runner.RunWith
    import org.spockframework.runtime.Sputnik
    import spock.lang.Subject
    import spock.lang.Unroll
    import spock.lang.Specification
    import org.powermock.core.classloader.annotations.PowerMockIgnore
    import org.powermock.core.classloader.annotations.PrepareForTest
    import org.powermock.modules.junit4.PowerMockRunner
    import org.powermock.modules.junit4.PowerMockRunnerDelegate
    
    /**
    * @Descriptioin
    * @Author ${author}
    * @Date ${date}
    */
    //@PowerMockIgnore("javax.net.ssl.*")看需使用
    @Subject(${className}.class)
    @RunWith(PowerMockRunner.class)
    @PowerMockRunnerDelegate(Sputnik.class)
    @PrepareForTest([])
    class ${className}Test extends Specification {
    
        <#list methodNameList as methodName>
        @Unroll
        def "${className}-${methodName}"() {
            given:
    
            when:
            ${classShortName}.${methodName}()
            then:
    
            where:
         }
        
    
    }
    

    BaseMockitoUnitTestGen.ftl

    ${package};
    
    import org.junit.Assert;
    import org.junit.Before;
    import org.junit.Test;
    import org.mockito.InjectMocks;
    import org.mockito.Mock;
    import org.mockito.Mockito;
    import org.mockito.MockitoAnnotations;
    <#list importList as import>
    import ${import};
    
    
    
    /**
    * 基本的Junit Runner
    * 可使用Springboot test集成的Mockito框架
    * 不能Mock静态方法,如果需要Mock静态方法需要使用PowerMockRunner
    * @Descriptioin
    * @Author ${author}
    * @Date ${date}
    */
    @RunWith(SpringRunner.class)
    @WebAppConfiguration
    @SpringBootTest
    @Transactional
    @Rollback
    public class ${className}Test {
    
        @InjectMocks
        private ${className} ${classShortName};
    
    <#list serviceList as service>
        @Mock
        private ${service.mockService} ${service.useService};
    
    
        @Before
        public void init() {
            MockitoAnnotations.initMocks(this);
        }
    
        <#list methodNameList as methodName>
        @Test
        public void ${methodName}Test() {
    
        }
        
    
    }
    

    StaticMockitoUnitTestGen.ftl

    ${package};
    
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.mockito.InjectMocks;
    import org.mockito.Mock;
    import org.mockito.MockitoAnnotations;
    import org.powermock.core.classloader.annotations.PowerMockIgnore;
    import org.powermock.core.classloader.annotations.PrepareForTest;
    import org.powermock.modules.junit4.PowerMockRunner;
    <#list importList as import>
    import ${import};
    
    
    
    /**
    * Powermock runner,不加载Spring上下文,否则在集成测试时会重复加载Spring上下文
    * 如果需要mock静态方法,final方法等Power增强操作
    * @Descriptioin
    * @Author ${author}
    * @Date ${date}
    */
    @RunWith(PowerMockRunner.class)
    @PowerMockIgnore({"javax.management.*"})
    @PrepareForTest()
    public class ${className}Test {
    
        @InjectMocks
        private ${className} ${classShortName};
    
    <#list serviceList as service>
        @Mock
        private ${service.mockService} ${service.useService};
    
    
        @Before
        public void init() {
            MockitoAnnotations.initMocks(this);
        }
    
        <#list methodNameList as methodName>
        @Test
        public void ${methodName}Test() {
    
        }
        
    
    }
    
  • 相关阅读:
    分布式互斥
    分支和循环
    Gitlab 安装
    Synchronized
    JUC P3 共享模型之无锁同步,CAS,原子类,Unsafe类 基础+代码
    【踩坑专栏】0%classes,0% lines covered
    OA项目之我的会议(会议排座&送审)
    复盘:智能座舱系列文三- 它背后的5种交互技术之触觉
    前端根据登录用户做不同权限控制
    YOLOX训练-COCO格式
  • 原文地址:https://blog.csdn.net/QQ563627436/article/details/127082423