groovy和mockito单测自动生成

groovy单测自动生成

以交易核心trade举例

前置准备

在这里插入图片描述

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

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

<dependency>
	<groupId>org.freemarker</groupId>
	<artifactId>freemarker</artifactId>
	<version>2.3.21</version>
	<scope>test</scope>
</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}
</#list>



/**
* 需要在原来的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})
</#list>

    @Override
    def init() {
    <#list serviceList as service>
        ${classShortName}.${service.useService} = ${service.useService}
    </#list>
    }

    @Override
    def clean() {
    <#list serviceList as service>
        ${classShortName}.${service.useService} = SpringContextUtil.getObject(${service.mockService}.class)
    </#list>
    }

    <#list methodNameList as methodName>
    @Unroll
    def "${className}-${methodName}"() {
        given:

        when:
        ${classShortName}.${methodName}()
        then:

        where:
     }

    </#list>

}

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:
     }
    </#list>

}

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};
</#list>


/**
* 基本的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};
</#list>

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }

    <#list methodNameList as methodName>
    @Test
    public void ${methodName}Test() {

    }
    </#list>

}

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};
</#list>


/**
* 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};
</#list>

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }

    <#list methodNameList as methodName>
    @Test
    public void ${methodName}Test() {

    }
    </#list>

}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值