如何提高单测覆盖率

相关工具推荐:

TestMe:用于快速生成测试类

一、抽象一个公共类,将TestMe的配置内容该类MockTest

import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;

import java.io.File;
import java.lang.reflect.Method;

/**
 * mock测试
 */
@RunWith(MockitoJUnitRunner.class)
@Slf4j
public abstract class MockTest {

    @Before
    public void init() {
        //公用设置
        Snowflake.init("127.0.0.1", 8080, true);
    }

    /**
     * 当代码中有需要访问某一个文件时,生成一个临时文件
     * @return
     */
    public String getTmpFilePath(){
        try {
            File mockFile = File.createTempFile("mock", ".txt");
            return mockFile.getPath();
        }catch (Exception e){
            log.error("file create error",e);
            return "";
        }
    }

    public File getTmpFile(){
        try {
            File mockFile = File.createTempFile("mock", ".txt");
            return mockFile;
        }catch (Exception e){
            log.error("file create error",e);
            return null;
        }
    }

    /**
     * 当私有方法较大,正常逻辑不好覆盖时,单测私有方法
     * @param obj
     * @param cla
     * @param instance
     * @param methodName
     * @param paramClass
     */
    public void invokeMethod(Object obj, Class cla, Object instance, String methodName,Class paramClass) {
        try {
            getMethod(methodName, cla,paramClass).invoke(instance, obj);
            //模拟失败
            getMethod(methodName, cla,paramClass).invoke(cla.newInstance(), obj);
        } catch (Exception e) {}
    }

    private Method getMethod(String methodName, Class cla, Class paramClass) throws Exception {
        Method method = cla.getDeclaredMethod(methodName, paramClass);
        method.setAccessible(true);
        return method;
    }
}

二、配置TestMe Templates

代码:

#parse("TestMe macros.java")
#set($hasMocks=$MockitoMockBuilder.hasMockable($TESTED_CLASS.fields))
#if($PACKAGE_NAME)
package ${PACKAGE_NAME};
#end

import static org.junit.Assert.*;
import org.junit.Test;
#if($hasMocks)
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.junit.Assert;
import com.替换路径.MockTest
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
#end

#parse("File Header.java")
@RunWith(MockitoJUnitRunner.class)
public class ${CLASS_NAME} extends MockTest{
#renderMockedFields($TESTED_CLASS.fields)

#renderTestSubjectInit($TESTED_CLASS,$TestSubjectUtils.hasTestableInstanceMethod($TESTED_CLASS.methods),$hasMocks)
#if($hasMocks)

    @Before
    public void setUp() {
        MockitoAnnotations.${MockitoMockBuilder.initMocksMethod}(this);
    }
#end
#foreach($method in $TESTED_CLASS.methods)
#if($TestSubjectUtils.shouldBeTested($method))

    @Test
    public void #renderTestMethodName($method.name)(){
#if($MockitoMockBuilder.shouldStub($method,$TESTED_CLASS.fields))
#renderMockStubs($method,$TESTED_CLASS.fields)

#end
        #renderMethodCall($method,$TESTED_CLASS.name)
        Assert.assertNotNull(new Object());

    }
#end
#end
}

 三、代码覆盖率提升技巧

针对所有的bean和枚举进行单测覆盖,可通用配置

import org.junit.Test;
import org.springframework.beans.BeanUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @author awen
 **/
public class CommonBeanTest {
    String CLASSPATH_ALL_URL_PREFIX = "classpath:";

    @Test
    public void beanTest() throws Exception {

        List<String> list = new ArrayList();
        list.add("com.xxx.bean");
        list.add("com.xxx.api");

        for (String path : list) {
            // 包名转路径
            path = path.replaceAll("\\.", "\\/");
            String packageSearchPath = CLASSPATH_ALL_URL_PREFIX + path + "/**/*.class";
            // 获取所有的Pojo类
            ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);
            // 遍历
            for (Resource r : resources) {
                // 获取类名
                String name = r.getURL().getPath();
                name = name.substring(name.indexOf("com"), name.lastIndexOf("."));
                name = name.replaceAll("/", ".");
                // 获取类对象
                Class c = this.getClass().getClassLoader().loadClass(name);
                if(c.isEnum()){
                    enumCover(c);
                }else if(!c.isInterface()){
                    copyBean(c);
                }
            }
        }
    }

    private void copyBean(Class c) throws Exception {
        try {
            // 生成两个实例
            Object dest = c.newInstance();
            Object orig = c.newInstance();
            // 测试toString方法
            dest.toString();
            // 测试Getter Setter方法
            BeanUtils.copyProperties(dest, orig);
        }catch (Exception e){
        }
    }

    private void enumCover(Class c){
        if(c.isEnum()){
            Object[] enumConstants = c.getEnumConstants();
            Object obj = enumConstants[0];

            for(Object enumConstant:enumConstants) {
                enumConstant.toString();
            }
            try{
                Method method = c.getMethod("getByCode",String.class);
                method.invoke(obj,obj.toString());
            }catch (Exception e){
            }

            try{
                Method method = c.getMethod("valueOf",String.class);
                method.invoke(obj,obj.toString());
            }catch (Exception e){}
        }
    }

}

其他技巧:

1、设置类中的私有变量:

ReflectionTestUtils.setField(被测试类实例,"变量",值);

2、实例化ApplicationContext,设置根据类型返回实例:

ApplicationContext applicationContext = Mockito.mock(ApplicationContext.class);
Map<String, 抽象类> map = Maps.newHashMap();
map.put("1",实例);
Mockito.when(applicationContext.getBeansOfType(抽象类.class)).thenReturn(map);

3、类中mock的方法时,如果有重载方法,可使用any(Class)转化为相关类型,再进行处理

when(类实例.方法(any(XXX.class),any(),any())).thenReturn(mock返回值);
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值