spring服务懒人测试秘籍,只需一个controller测试所有bean的方法

前言

在使用spring实际生产开发中,写完代码需要测试,如果不想写测试用例,也不想写controller来测试怎么办,经常一些非http服务测试会十分麻烦,如果要写controller或者是单元测试去测,需要大量的时间,当然时间足够还是写单元测试好一些,但是懒人就是不想写,然后又想测试完善以免测试不完全。本文提供一个比较好的操作去解决这些问题。

代码编写

这里用一个controller方法去暴露一个http接口,通过反射和spring的通过bean name去找bean示例,来实现一个接口测所有方法。首先,定义一个beanFactory来获取bean

@Component
public class BeanFactoryTest implements ApplicationContextAware {
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }
}

然后定义一个controller方法:

/**
     *
     * @param beanName 调用的bean的名字
     * @param methodName 调用方法名
     * @param paramsClassName 调用方法入参的class name
     * @param params 调用方法的入参String
     * @return 结果
     * @throws ClassNotFoundException 不管
     * @throws InvocationTargetException 不管
     * @throws IllegalAccessException 不管
     * @throws NoSuchMethodException 不管
     */
    @RequestMapping("/testAll")
    @TryLogin
    public String testAll(String beanName,String methodName,String[] paramsClassName,String[] params) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        //根据名字获取bean示例对象
        Object object = beanFactoryTest.getApplicationContext().getBean(beanName);
        //创建入参class数组
        Class[] argsClass = new Class[paramsClassName.length];
        //创建入参obj数组
        Object[] paramObj = new Object[paramsClassName.length];
        for (int i = 0; i < paramsClassName.length; i++) {
            //用自写的class forName通过类名去获取class
            argsClass[i] = aClassForName(paramsClassName[i]);
            //巧妙操作,通过fastJson来做类型转换,实测所有类型可转,int,long这种基本类型也可以
            paramObj[i] = JSONObject.parseObject(params[i], aClassForName(paramsClassName[i]));
        }
        //通过方法名,和参数类型class,找到方法
        Method method = object.getClass().getMethod(methodName,argsClass);
        assert method != null;
        //取消权限检查,可以调用private
        method.setAccessible(true);
        //执行方法
        Object result = method.invoke(object, paramObj);
        //返回执行结果,用json序列化后显示
        return JSONObject.toJSONString(result);
    }

这里面aClassForName是重写的一个通过类名去查找class,因为java基本类型无法通过Class.forName来查找,Class.getPrimitiveClass又是protect方法,所以自己写一个。代码十分简单,如下:

public Class<?> aClassForName(String name) throws ClassNotFoundException {
        switch (name){
            case "int":
                return int.class;
            case "boolean":
                return boolean.class;
            case "long":
                return long.class;
            case "byte":
                return byte.class;
            case "short":
                return short.class;
            case "float":
                return float.class;
            case "double":
                return double.class;
            case "char":
                return char.class;
            default:
                return Class.forName(name);
        }

ok,完事了,就是这么简单。

测试及注意事项

image.png

如图,直接测试redis的一个sevice。原方法如下

public Long incr(String key,long step,long expire){
        Long value = stringRedisTemplate.opsForValue().increment(key,step);
        stringRedisTemplate.expire(key,expire, TimeUnit.SECONDS);
        return value;
    }

可以从上图截图中看到方法有返回,我连续请求调用了两次,返回了2。

这里需要注意的是使用 JSONObject.parseObject吧任何类型从String转为某种类型,如果是int,long,Long,之类的直接写就行,如果是map,set,list,或者是自己定义的类,用json规范写就ok,需要特别注意的是String类型的话,这一步就是String转String,所以String应该是这种格式"\"i am a String\""。这里是postman里面,可以不用反斜杠转码。

到这里你有没有发现,这不仅仅是个测试接口,更是个可以调用任意bean方法的后门,用反射原理,随便再改改,什么方法都能调,什么实例都能改。

最后劝告,生产别直接带上去,配置开关或者权限,或者不要带上。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值