日常中的开发工作,大部分都是增删改查,所以和SQL打交道的时候特别多,我在日常工作中,使用的最多的是mybatis和mysql,用的是spring boot框架,所以在改完代码之后,全量测试下SQL是否正确,就非常重要了。有时候单元测试没来得及写全,所以有一个简单的工具,可以做一下冒烟测试,也是非常有必要的,可以避免低级错误。
所以就萌生了一个想法,通过反射,获取系统中的所有的SQL,挨个执行一遍,简单测试下SQL是否报错。
PS: 如果想要做精细化的测试,还需要自己单独写单元测试。
1、说干就干
思路明确了,先去网上搜索下,有没有别人已经做过了。简单搜了下,确实有人做过,必须要传入dao文件的物理路径,然后解析文件,这明显不是我想要的效果。
通过spring boot拿所有的代理类,没有行的通,失败。
通过反射拿所有的类,需要硬编码所有的dao的名字,失败。
相继失败之后,研究了下mybatis原理,发现所有的代理类,都封装成了MapperFactoryBean,通过ApplicationContext拿所有的这个类,成功。
2、一些挫折
拿到了 MapperFactoryBean之后,却怎么也拿不到MapperProxy,MapperProxy是mybatis的代理类,本来想强制转换的,结果一直报com.sun.proxy.$80Proxy不能转换为MapperProxy,郁闷,必须转换下思路。
3、解决
反射执行方法,是method.invoke(obj,param); obj是不是不需要转换? 我的天,绕弯路了,根本不需要转换得到MapperProxy,直接就解决了,剩下的问题就比较简单了。
- 拿到dao类,反射得到所有的方法。
- 解析方法的参数,使用随机工具类,生成测试参数。
- 对于long类型的id,控制下范围。
- 对于string类型的,控制下长度,毕竟数据库里的varchar,一般都有最大长度。
4、代码
直接看代码吧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| @Test public void testAllDao() throws Throwable {
Map<String, MapperFactoryBean> map = SpringContextUtil.getApplicationContext().getBeansOfType(org.mybatis.spring.mapper.MapperFactoryBean.class); for (Map.Entry<String, MapperFactoryBean> entry : map.entrySet()) { MapperFactoryBean mapperFactoryBean = entry.getValue(); Class clz2 = mapperFactoryBean.getMapperInterface(); Object object = mapperFactoryBean.getObject(); Method[] methods = clz2.getMethods(); for (Method method : methods) { Class[] paramClz = method.getParameterTypes(); Object[] param = new Object[paramClz.length]; for (int i = 0; i < paramClz.length; i++) { param[i] = newInstance(paramClz[i]); } try { method.invoke(object, param); System.out.println("执行class " + clz2.getName() + " 方法 " + method.getName() + " 成功"); } catch (Exception e) { System.out.println("执行class " + clz2.getName() + " 方法 " + method.getName() + " 异常"); e.printStackTrace(); } }
} System.out.println("执行结束。。。。。。。。。。。。"); }
|
4、小结
遇到问题不要慌,先网上搜,再看原理,遇到问题,都需要先假设犯了低级错误。