美文网首页Java
spring服务懒人测试秘籍,只需一个controller测试所

spring服务懒人测试秘籍,只需一个controller测试所

作者: 一个没有感情的程序员 | 来源:发表于2021-05-26 20:34 被阅读0次

    前言

    在使用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方法的后门,用反射原理,随便再改改,什么方法都能调,什么实例都能改。

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

    相关文章

      网友评论

        本文标题:spring服务懒人测试秘籍,只需一个controller测试所

        本文链接:https://www.haomeiwen.com/subject/dlhlsltx.html